# Invoke <VersionBadge version="v3.7.0+" />
Source: https://www.inngest.com/docs/reference/functions/step-invoke

description = `Calling Inngest functions directly from other functions with step.invoke()`

Use `step.invoke()` to asynchronously call another function and handle the result. Invoking other functions allows you to easily re-use functionality and compose them to create more complex workflows or map-reduce type jobs. `step.invoke()` returns a `Promise` that resolves with the return value of the invoked function.

```ts
// Some function we'll call
inngest.createFunction(
  { id: "compute-square" },
  { event: "calculate/square" },
  async ({ event }) => {
    return { result: event.data.number * event.data.number }; // Result typed as { result: number }
  }
);

// In this function, we'll call `computeSquare`
inngest.createFunction(
  { id: "main-function" },
  { event: "main/event" },
  async ({ step }) => {
    await step.invoke("compute-square-value", {
      function: computeSquare,
      data: { number: 4 }, // input data is typed, requiring input if it's needed
    });

    return `Square of 4 is ${square.result}.`; // square.result is typed as number
  }
);
```

## `step.invoke(id, options): Promise`

<Row>
  <Col>
    <Properties>
      <Property name="id" type="string" required>
        The ID of the invocation. This is used in logs and to keep track of the invocation's state across different versions.
      </Property>
      <Property name="options" type="object" required>
        Options for the invocation:
        <Properties nested={true}>
          <Property name="function" type="InngestFunction | InngestFunctionReference" required>
            A local instance of a function or a reference to a function to invoke.
          </Property>
          <Property name="data" type="object">
            Optional data to pass to the invoked function. Will be required and typed if it can be.
          </Property>
          <Property name="user" type="object">
            Optional user context for the invocation.
          </Property>
          <Property name="timeout" type="string | number | Date" version="v3.14.0+">
            {/* Purposefully not mentioning the default timeout of 1 year, as we expect to lower this very soon. */}
            The amount of time to wait for the invoked function to complete. The time to wait can be specified using a `number` of milliseconds, an `ms`-compatible time string like `"1 hour"`, `"30 mins"`, or `"2.5d"`, or a `Date` object.

            If the timeout is reached, the step will throw an error. See [Error handling](#error-handling) below. Note that the invoked function will continue to run even if this step times out.
          </Property>
        </Properties>
        Throwing errors within the invoked function will be reflected in the invoking function.
      </Property>
    </Properties>
  </Col>
  <Col>
    <CodeGroup title="Invoke a function directly">
    ```ts
    await step.invoke("invoke-by-definition", {
      function: anotherFunction,
      data: { ... },
    });
    ```
    </CodeGroup>
    <CodeGroup title="Invoke a function using a function reference">
    ```ts
    await step.invoke("invoke-by-reference", {
      function: referenceFunction(...),
      data: { ... },
    });
    ```
    </CodeGroup>
    <CodeGroup title="Invoke a function with a timeout">
    ```ts
    await step.invoke("invoke-with-timeout", {
      function: anotherFunction,
      data: { ... },
      timeout: "1h",
    });
    ```
    </CodeGroup>
  </Col>
</Row>

## How to call `step.invoke()`

Handling `step.invoke()` is similar to handling any other Promise in JavaScript:

```ts
// Using the "await" keyword
await step.invoke("invoke-function", {
  function: someInngestFn,
  data: { ... },
});

// Using `then` for chaining
step
  .invoke("invoke-function", { function: someInngestFn, data: { ... } })
  .then((result) => {
    // further processing
  });

// Running multiple invocations in parallel
Promise.all([
  step.invoke("invoke-first-function", {
    function: firstFunctionReference,
    data: { ... },
  }),
  step.invoke("invoke-second-function", {
    function: secondFn,
    data: { ... },
  }),
]);
```

## Using function references

Instead of directly importing a local function to invoke, [`referenceFunction()`](/docs/functions/references) can be used to call an Inngest function located in another app, or to avoid importing the dependencies of a function within the same app.

```ts
// Create a local reference to a function without importing dependencies
referenceFunction<typeof computePi>({
  functionId: "compute-pi",
});

// Create a reference to a function in another application
referenceFunction({
  appId: "my-python-app",
  functionId: "compute-square",
});

// square.result is typed as a number
await step.invoke("compute-square-value", {
  function: computePi,
  data: { number: 4 }, // input data is typed, requiring input if it's needed
});
```

See [Referencing functions](/docs/functions/references) for more information.

## When to use `step.invoke()`

Use of `step.invoke()` to call an Inngest function directly is more akin to traditional RPC than Inngest's usual event-driven flow. While this tool still uses events behind the scenes, you can use it to help break up your codebase into reusable workflows that can be called from anywhere.

Use `step.invoke()` in tasks that need specific settings like concurrency limits. Because it runs with its own configuration,
distinct from the invoker's, you can provide a tailored configuration for each function.

If you don't need to define granular configuration or if your function won't be reused across app boundaries, use `step.run()` for simplicity.

## Internal behaviour

When a function object is passed as an argument, internally, the SDK retrieves the function's ID automatically. Alternatively, if a function ID `string` is passed, the Inngest SDK will assert the ID is correct at runtime. See [Error handling](#error-handling) for more information about this point.

When Inngest receives the request to invoke a function, it'll do so and wait for an `inngest/function.finished` event, which it will use to fulfil the data (or error) for the step.

## Return values and serialization

Similar to `step.run()`, all data returned from `step.invoke()` is serialized as JSON. This is done to enable the SDK to return a valid serialized response to the Inngest service.

## Timeout
If not explicity configured, the default timeout for `step.invoke` is 1 year. 

## Retries

The invoked function will be executed as a regular Inngest function: it will have its own set of retries and can be seen as a brand new run.

If a `step.invoke()` fails for any of the reasons below, it will throw a `NonRetriableError`. This is to combat compounding retries, such that chains of invoked functions can be executed many more times than expected. For example, if A invokes B which invokes C, which invokes D, on failure D would be run 27 times (`retryCount^n`).

This may change on the future - [let us know](https://roadmap.inngest.com/roadmap?ref=docs) if you'd like to change this.

## Error handling

### Function not found

If Inngest could not find a function to invoke using the given ID (see [Internal behaviour](#internal-behaviour) above), an `inngest/function.finished` event will be sent with an appropriate error and the step will fail with a `NonRetriableError`.

### Invoked function fails

If the function exhausts all retries and fails, an `inngest/function.finished`
event will be sent with an appropriate error and the step will fail with a
`NonRetriableError`.

### Invoked function times out

If the `timeout` has been reached and the invoked function is still running, the
step will fail with a `NonRetriableError`.

### Invoked function is rate limited

If the called function has a rate limit configuration and is skipped, the step will fail with a `NonRetriableError`.
It's recommended to wrap the `step.invoke` with a `try catch` if the invoked function is expected to be executing occasionally.

### Invoked function is debounced

If the called function has a debounce configuration and is skipped, the step will fail with a `NonRetriableError` after the timeout has been reached. It is preferable to always set a meaningful timeout when invoking a function with debounce configuration.

## Usage limits

See [usage limits][usage-limits] for more details.

[usage-limits]: /docs/usage-limits/inngest#functions