# Middleware lifecycle <VersionBadge version="v2.0.0+" />
Source: https://www.inngest.com/docs/reference/middleware/lifecycle

## Hook reference

The `init()` function can return functions for two separate lifecycles to hook into.

<Callout>
💡 All lifecycle and hook functions can be synchronous or `async` functions - the SDK will always wait until a middleware's function has resolved before continuing to the next one.
</Callout>

<Row>
     <Col>
          ### `onFunctionRun` lifecycle

          Triggered when a function is going to be executed.

          <Properties name="Arguments" nested>
               <Property name="ctx" type="object">
                    The input data for the function. Only `event` and `runId` are available at this point.
               </Property>
               <Property name="steps" type="array">
                    An array of previously-completed step objects.

                    <Properties nested collapse>
                      <Property name="data" type="any">
                        The serialized data for this step if it was successful.
                      </Property>
                      <Property name="error" type="any">
                        The serialized error for this step if it failed.
                      </Property>
                    </Properties>
               </Property>
               <Property name="fn" type="InngestFunction">
                    The function that is about to be executed.
               </Property>
               <Property name="reqArgs" type="array" version="v3.9.0+">
                    Arguments passed to the framework's request handler, which are used by the SDK's `serve` handler.
               </Property>
          </Properties>

          <Properties name="Returns" nested>
               <Property name="transformInput" type="function">
                    Called once the input for the function has been set up. This is where you can modify the input before the function starts.

                    Has the same input as the containing `onFunctionRun()` lifecycle function, but with a complete `ctx` object, including `step` tooling.

                    <Properties name="Returns" nested collapse>
                         <Property name="ctx" type="object">
                              An object that will be merged with the existing function input to create a new input.
                         </Property>
                         <Property name="steps" type="array">
                              An array of modified step data to use in place of the current step data.
                         </Property>
                    </Properties>
               </Property>
               <Property name="beforeMemoization" type="function">
                    Called before the function starts to memoize state (running over previously-seen code).
               </Property>
               <Property name="afterMemoization" type="function">
                    Called after the function has finished memoizing state (running over previously-seen code).
               </Property>
               <Property name="beforeExecution" type="function">
                    Called before any step or code executes.
               </Property>
               <Property name="afterExecution" type="function">
                    Called after any step or code has finished executing.
               </Property>
               <Property name="transformOutput" type="function">
                    Called after the function has finished executing and before the response is sent back to Inngest. This is where you can modify the output.

                    <Properties name="Arguments" nested collapse>
                         <Property name="result" type="object" required>
                              An object containing the data to be sent back to Inngest in the `data` key, and an original `error` (if any) that threw.
                         </Property>
                         <Property name="step" type="object">
                              If this execution ran a step, will be a step that ran.
                         </Property>
                    </Properties>

                    <Properties name="Returns" nested collapse>
                         <Property name="result" type="object">
                              An object containing a `data` key to overwrite the data that will be sent back to Inngest for this step or function.
                         </Property>
                    </Properties>
               </Property>
               <Property name="finished" type="function" version="v3.21.0+">
                    Called when execution is complete and a final response is returned (success or an error), which will end the run.

                    This function is not guaranteed to be called on every execution. It may be called multiple times if there are many parallel executions or during retries.

                    <Properties name="Arguments" nested collapse>
                          <Property name="result" type="object" required>
                              An object that contains either the successful `data` ending the run or the `error` that has been thrown. Both outputs have already been affected by `transformOutput`.
                          </Property>
                    </Properties>
               </Property>
               <Property name="beforeResponse" type="function">
                    Called after the output has been set and before the response has been sent back to Inngest. Use this to perform any final actions before the request closes.
               </Property>
          </Properties>
     </Col>
     <Col>
          ```ts
          new InngestMiddleware({
            name: "My Middleware",
            init({ client, fn }) {
              return {
                onFunctionRun({ ctx, fn, steps }) {
                  return {
                    transformInput({ ctx, fn, steps }) {
                      // ...
                      return {
                        // All returns are optional
                        ctx: { /* extend fn input */ },
                        steps: steps.map(({ data }) => { /* transform step data */ })
                      }
                    },
                    beforeMemoization() {
                      // ...
                    },
                    afterMemoization() {
                      // ...
                    },
                    beforeExecution() {
                      // ...
                    },
                    afterExecution() {
                      // ...
                    },
                    transformOutput({ result, step }) {
                      // ...
                      return {
                        // All returns are optional
                        result: {
                          // Transform data before it goes back to Inngest
                          data: transformData(result.data)
                        }
                      }
                    },
                    finished({ result }) {
                      // ...
                    },
                    beforeResponse() {
                      // ...
                    },
                  };
                },
              };
            },
          });
          ```
     </Col>
</Row>

---

<Row>
     <Col>
          ### `onSendEvent` lifecycle

          Triggered when an event is going to be sent via `inngest.send()`, `step.sendEvent()`, or `step.invoke()`.

          <Properties name="Output" nested>
               <Property name="transformInput" type="function">
                    Called before the events are sent to Inngest. This is where you can modify the events before they're sent.
               </Property>
               <Property name="transformOutput" type="function">
                    Called after events are sent to Inngest. This is where you can perform any final actions and modify the output from `inngest.send()`.
               </Property>
          </Properties>
     </Col>
     <Col>
          ```ts
          new InngestMiddleware({
            name: "My Middleware",
            init: ({ client, fn }) => {
              return {
                onSendEvent() {
                  return {
                    transformInput({ payloads }) {
                      // ...
                    },
                    transformOutput() {
                      // ...
                    },
                  };
                },
              };
            },
          });
          ```
     </Col>
</Row>