# Run

Use `step.run()` to run synchronous or asynchronous code as a retriable step in your function. `step.run()` returns a [Promise](https://developer.mozilla.org/en-US/docs-markdown/Web/JavaScript/Reference/Global_Objects/Promise) that resolves with the return value of your handler function.

```ts
export default inngest.createFunction(
  {
    id: "import-product-images",
    triggers: { event: "shop/product.imported" },
  },
  async ({ event, step }) => {
    const uploadedImageURLs = await step.run("copy-images-to-s3", async () => {
      return copyAllImagesToS3(event.data.imageURLs);
    });
  }
);
```

***

## `step.run(id, handler): Promise`

- `id` (string): The ID of the step. This will be what appears in your function's logs and is used to memoize step state across function versions.

* `handler` (function): The function that code that you want to run and automatically retry for this step. Functions can be:A synchronous functionAn async functionAny function that returns a PromiseThrowing errors within the handler function will trigger the step to be retried (reference).

```ts
// Steps can have async handlers
const result = await step.run("get-api-data", async () => {
  // Steps should return data used in other steps
  return fetch("...").json();
});

// Steps can have synchronous handlers
const data = await step.run("transform", () => {
  return transformData(result);
});

// Returning data is optional
await step.run("insert-data", async () => {
  db.insert(data);
});

```

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

As `step.run()` returns a [Promise](https://developer.mozilla.org/en-US/docs-markdown/Web/JavaScript/Reference/Global_Objects/Promise), you will need to handle it like any other Promise in JavaScript. Here are some ways you can use `step.run()` in your code:

```ts
// Use the "await" keyword to wait for the promise to fulfil
await step.run("create-user", () => {/* ... */});
const user = await step.run("create-user", () => {/* ... */});

// Use `then` (or similar)
step.run("create-user", () => {/* ... */})
  .then((user) => {
    // do something else
  });

// Use with a Promise helper function to run in parallel
Promise.all([
  step.run("create-subscription", () => {/* ... */}),
  step.run("add-to-crm", () => {/* ... */}),
  step.run("send-welcome-email", () => {/* ... */}),
]);
```

## Retries

Each `step.run()` call has its own independent retry counter. When a step throws an error, it will be retried according to your function's retry configuration. The retry configuration applies to each individual step, not as a shared pool across all steps in your function.

For example, if your function is configured with `retries: 4`, each `step.run()` will be retried up to 4 times independently (5 total attempts including the initial attempt). If you have multiple steps in your function, each step gets its own full set of retries.

Learn more about [configuring retries](/docs-markdown/features/inngest-functions/error-retries/retries).

## Return values and serialization

All data returned from `step.run` is serialized as JSON. This is done to enable the SDK to return a valid serialized response to the Inngest service.

```ts
const output = await step.run("create-user", () => {
  return { id: new ObjectId(), createdAt: new Date() };
});
/*
{
  "id": "647731d1759aa55be43b975d",
  "createdAt": "2023-05-31T11:39:18.097Z"
}
*/
```

## Usage limits

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

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