> ## Documentation Index
> Fetch the complete documentation index at: https://trigger-features-scheduled-tasks.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# io.runTask()

> Creates and runs a Task inside a Run.

A [Task](/documentation/concepts/tasks) is a cached unit of work in a Job Run that are logged to the Trigger.dev UI. You can use `io.runTask()` to create and run a Task inside a Run.

<Warning>
  Any interaction with an external service (database or API) should be wrapped in a Task. Failing to
  do so could result in repeated work when runs are resumed.
</Warning>

## Parameters

<Snippet file="stable-key-param.mdx" />

<ResponseField name="callback" type="function" required>
  The callback that will be called when the Task is run, this is where your logic should go. The callback receives
  the Task and the IO as parameters.

  <Expandable title="arguments">
    <ResponseField name="task" type="Task">
      The Task that is running. It has some useful properties like `idempotencyKey` and `attempts`.
    </ResponseField>

    <ResponseField name="io" type="IO">
      [IO](/sdk/io/overview) holds Integrations and useful actions you can perform.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="options" type="object">
  The options of how you'd like to run and log the Task.

  <Expandable title="options">
    <ResponseField name="name" type="string">
      This is displayed on the Task in the logs.
    </ResponseField>

    <ResponseField name="delayUntil" type="date">
      The Task will wait and only start at the specified Date.
    </ResponseField>

    <ResponseField name="retry" type="object">
      Retry options.

      <Expandable title="options">
        <ResponseField name="limit" type="number">
          The maximum number of times to retry the request.
        </ResponseField>

        <ResponseField name="minTimeoutInMs" type="number">
          The minimum amount of time to wait before retrying the request.
        </ResponseField>

        <ResponseField name="maxTimeoutInMs" type="number">
          The maximum amount of time to wait before retrying the request.
        </ResponseField>

        <ResponseField name="factor" type="number">
          The exponential factor to use when calculating the next retry time.
        </ResponseField>

        <ResponseField name="randomize" type="boolean">
          Whether to randomize the retry time.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="icon" type="string">
      The icon for the Task, it will appear in the logs. You can use the name of a
      company in lowercase, e.g. "github". Or any icon name that [Tabler Icons](https://tabler-icons.io/) supports.
    </ResponseField>

    <ResponseField name="description" type="string">
      A description of the Task.
    </ResponseField>

    <ResponseField name="properties" type="array">
      Properties that are displayed in the logs.

      Each property has the following fields:

      <Expandable title="property fields">
        <ResponseField name="label" type="string" required>
          The label for the property.
        </ResponseField>

        <ResponseField name="text" type="string" required>
          The value of the property.
        </ResponseField>

        <ResponseField name="url" type="string">
          The URL to link to when the property is clicked.
        </ResponseField>
      </Expandable>
    </ResponseField>

    {" "}

    <ResponseField name="params" type="any">
      The input params to the Task, will be displayed in the logs.
    </ResponseField>

    <ResponseField name="style" type="object">
      The style of the log entry.

      <Expandable title="style">
        <ResponseField name="style" type="string">
          The style: `normal` or `minimal`.
        </ResponseField>

        <ResponseField name="variant" type="string">
          A variant of the style.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="redact" type="RedactOptions">
      An optional object that specifies which fields to redact from the logs. This is useful for sensitive data like API keys.

      <Expandable title="redact" defaultOpen>
        <ResponseField name="paths" type="string[]">
          An array of paths to redact. A path is a dot separated string, e.g. `user.email`. Currently does not support wildcards.
        </ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="callback" type="object">
      An optional object that exposes settings for the remote callback feature.

      Enabling this feature will expose a `callbackUrl` property on the callback's Task parameter. Additionally, `io.runTask()` will now return a Promise that resolves with the body of the first request sent to that URL.

      <Expandable title="property fields">
        <ResponseField name="enabled" type="boolean" required>
          Whether to enable the remote callback feature.
        </ResponseField>

        <ResponseField name="timeoutInSeconds" type="number" required>
          The value of the property.
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="onError" type="function">
  An optional callback that will be called when the Task fails. You can perform
  logic in here and optionally return a custom error object. Returning an object with `{ retryAt: Date, error?: Error }` will retry the Task at the specified Date. You can also just return a new `Error` object to throw a new error. Returning `null` or `undefined` will rethrow the original error. If you want to force retrying to be skipped, return `{ skipRetrying: true }`.

  <Expandable title="arguments">
    <ResponseField name="error" type="unknown">
      The underlying error that was thrown inside the Task callback.
    </ResponseField>

    <ResponseField name="task" type="Task">
      The Task that failed.
    </ResponseField>
  </Expandable>
</ResponseField>

## Returns

A Promise that resolves with the returned value of the callback.

If the remote callback feature `options.callback` is enabled, the Promise will instead resolve with the body of the first request sent to `task.callbackUrl`.

<RequestExample>
  ```typescript Run a task
  client.defineJob({
    id: "alert-on-new-github-issues",
    name: "Alert on new GitHub issues",
    version: "1.0.0",
    trigger: github.triggers.repo({
      event: events.onIssueOpened,
      owner: "triggerdotdev",
      repo: "trigger.dev",
    }),
    run: async (payload, io, ctx) => {
      const record = await io.runTask(
        "sync-github-issue",
        async (task) => {
          return prisma.githubIssues.create({
            data: {
              number: payload.issue.number,
              title: payload.issue.title,
              body: payload.issue.body,
              url: payload.issue.html_url,
              repo: payload.repository.full_name,
              owner: payload.repository.owner.login,
            },
          });
        },
        //this is optional
        { name: "Sync GitHub Issue", icon: "github" }
      );
    },
  });
  ```

  ```typescript onError callback
  client.defineJob({
    id: "custom-error-handling",
    name: "Custom Error handling",
    version: "0.1.1",
    trigger: eventTrigger({ name: "test" }),
    run: async (payload, io, ctx) => {
      //runTask
      const response = await io.runTask(
        "on-error-test",
        async () => {
          // Only throw error 50% of the time
          if (Math.random() > 0.5) {
            throw new Error("Something went wrong");
          }
        },
        { name: "On Error" },
        (error, task) => {
          //retry the task in 5 minutes
          return {
            retryAt: new Date(Date.now() + 5 * 60 * 1000),
            error: new Error("Something went REALLY wrong")
          };
        }
      );

      //log the url of the created card
      await io.logger.info(response.data.url);
    },
  });
  ```

  ```typescript Remote callbacks
  client.defineJob({
    id: "remote-callback-example",
    name: "Remote Callback example",
    version: "0.1.1",
    trigger: eventTrigger({ name: "predict" }),
    run: async (payload, io, ctx) => {
      const prediction = await io.runTask(
        "create-and-await-prediction",
        async (task) => {
          //create a prediction using a Replicate SDK instance
          await replicate.predictions.create({
            ...payload,
            webhook: task.callbackUrl ?? "",
            webhook_events_filter: ["completed"],
          });
          //the actual return value will be the data sent to callbackUrl
          //cast to the exact data type you expect to receive or `any` if unsure
          return {} as Prediction;
        },
        {
          name: "Create and await Prediction",
          icon: "replicate",
          //remote callback settings
          callback: {
            enabled: true,
            timeoutInSeconds: 300,
          },
        }
      );

      //log the prediction output
      await io.logger.info(prediction.output);
    },
  });
  ```
</RequestExample>
