Skip to content

Tasks Overview

Tasks are the core building block of Trigger.dev. A task is an async function with a unique ID that can be triggered, queued, retried, and monitored.

Hello World Task

ts
// /trigger/hello-world.ts
import { task } from "@trigger.dev/sdk";

const helloWorld = task({
  id: "hello-world",
  run: async (payload: { message: string }) => {
    console.log(payload.message);
    return { success: true };
  },
});

Trigger it from your backend:

ts
import { helloWorld } from "./trigger/hello-world";
const handle = await helloWorld.trigger({ message: "Hello world!" });

Task Options

id (required)

Unique string identifier for the task. Used for triggering, management, and dashboard views.

run function

Your async task code. Receives:

  1. payload — the data passed when triggered
  2. { ctx } — context about the run

Return value becomes the task output (must be JSON serializable).

retry

ts
retry: {
  maxAttempts: 10,
  factor: 1.8,
  minTimeoutInMs: 500,
  maxTimeoutInMs: 30_000,
  randomize: false,
}

Default: 3 retries. A task is retried if an error is thrown.

queue

ts
queue: {
  concurrencyLimit: 1, // max parallel runs
}

machine

ts
machine: {
  preset: "large-1x", // 4 vCPU, 8 GB RAM
}

Available presets: micro, small-1x, small-2x, medium-1x, medium-2x, large-1x, large-2x.

maxDuration

ts
maxDuration: 300, // 300 seconds = 5 minutes

Prevents a task from running too long.

Lifecycle Hooks

Per-task hooks

ts
export const myTask = task({
  id: "my-task",
  onStartAttempt: async ({ ctx }) => { /* before each attempt */ },
  onWait: async ({ ctx }) => { /* when task pauses */ },
  onResume: async ({ ctx }) => { /* when task resumes */ },
  onSuccess: async ({ ctx, output }) => { /* after success */ },
  onFailure: async ({ ctx, error }) => { /* after all retries exhausted */ },
  onComplete: async ({ ctx }) => { /* success or failure */ },
  onCancel: async ({ ctx }) => { /* when cancelled */ },
  run: async (payload, { ctx }) => { /* ... */ },
});

middleware and locals

The middleware system runs at the top level, before and after all lifecycle hooks:

ts
import { locals, tasks } from "@trigger.dev/sdk";

const DbLocal = locals.create<{ connect: () => Promise<void>; disconnect: () => Promise<void> }>("db");

tasks.middleware("db", async ({ ctx, payload, next }) => {
  const db = locals.set(DbLocal, { /* ... */ });
  await db.connect();
  await next();
  await db.disconnect();
});

catchError

Control error handling and retry behavior:

ts
export const myTask = task({
  id: "my-task",
  catchError: async (error, ctx) => {
    if (error.message.includes("rate limit")) {
      return { retry: { delay: "60s" } };
    }
    throw error; // re-throw to use default retry
  },
  run: async (payload) => { /* ... */ },
});

Global Lifecycle Hooks

Register in init.ts at the root of your trigger directory:

ts
// /trigger/init.ts
import { tasks } from "@trigger.dev/sdk";

tasks.onStart(({ ctx, payload, task }) => {
  console.log("Run started", ctx.run.id);
});

tasks.onSuccess(({ ctx, output }) => {
  console.log("Run finished", ctx.run.id);
});

tasks.onFailure(({ ctx, error }) => {
  console.log("Run failed", ctx.run.id, error);
});

Task Types

Built from official Trigger.dev documentation