Skip to main content
Waiting allows you to write complex tasks as straightforward async code. A waiting task releases its compute slot and only resumes when ready — you are not charged for idle time above 5 seconds.
FunctionWhat it does
wait.for()Waits for a specific duration, e.g. 1 day.
wait.until()Waits until a specific Date.
wait.forToken()Pauses a run until an external token is completed.
All wait functions must be called from inside a task.run() block. They will throw if called outside one.

wait.for()

Pause execution for a fixed duration. Supported units: seconds, minutes, hours, days, weeks, months, years.
/trigger/wait-for-example.ts
import { task, wait } from "@trigger.dev/sdk";

export const waitForExample = task({
  id: "wait-for-example",
  run: async (payload: { message: string }) => {
    console.log("Starting...");

    await wait.for({ seconds: 30 });
    await wait.for({ minutes: 5 });
    await wait.for({ hours: 2 });
    await wait.for({ days: 1 });
    await wait.for({ weeks: 1 });

    console.log("Resuming after wait.");
  },
});
Waits of 5 seconds or less count towards compute usage because the task does not checkpoint — it stays resident in memory.

Idempotency

Use idempotencyKey to ensure a wait is only registered once if the task retries:
import { task, wait } from "@trigger.dev/sdk";

export const idempotentWait = task({
  id: "idempotent-wait",
  run: async (payload: any) => {
    // Even if this task retries, the wait is only registered once
    await wait.for({ hours: 1 }, { idempotencyKey: "my-unique-wait-key" });
  },
});

wait.until()

Pause execution until a specific Date:
/trigger/wait-until-example.ts
import { task, wait } from "@trigger.dev/sdk";

export const waitUntilExample = task({
  id: "wait-until-example",
  run: async (payload: { resumeAt: string }) => {
    const resumeDate = new Date(payload.resumeAt);

    // Wait until a specific date
    await wait.until({ date: resumeDate });

    console.log("Resumed at", new Date().toISOString());
  },
});
Pass throwIfInThePast: true to throw an error if the date has already passed:
await wait.until({ date: new Date("2025-01-01"), throwIfInThePast: true });

wait.forToken()

Pause a run until an external event completes a token. This is useful for human-in-the-loop workflows, webhooks from third-party services, or any external approval step.

How it works

1

Create a token

Inside your task, create a waitpoint token. The token has a URL that can be called to complete it.
/trigger/approval-task.ts
import { task, wait } from "@trigger.dev/sdk";

export const approvalTask = task({
  id: "approval-task",
  run: async (payload: { documentId: string }) => {
    const token = await wait.createToken({
      // Prevent duplicate tokens if the task retries
      idempotencyKey: `approve-document-${payload.documentId}`,
      // Automatically complete the token as failed after this duration
      timeout: "24h",
      tags: [`document-${payload.documentId}`],
    });

    // Send the token URL to an external system or a human reviewer
    await sendReviewEmail({
      documentId: payload.documentId,
      approvalUrl: token.url,
    });

    // Pause until the token is completed or times out
    const result = await wait.forToken<{ approved: boolean; comment: string }>(token);

    if (!result.ok) {
      // Token timed out
      throw result.error;
    }

    return result.output; // { approved: boolean, comment: string }
  },
});
2

Complete the token

From anywhere in your codebase — or via HTTP callback — complete the token with a result:
import { wait } from "@trigger.dev/sdk";

// Complete the token with data
await wait.completeToken(token.id, {
  approved: true,
  comment: "Looks good!",
});
Or POST JSON to the token URL directly (useful for webhooks):
curl -X POST https://trigger.dev/api/v1/waitpoints/tokens/<TOKEN_ID>/complete \
  -H "Content-Type: application/json" \
  -d '{"approved": true, "comment": "Looks good!"}'

Using wait.forToken() with webhooks

This pattern is ideal for integrating with services that support webhooks:
/trigger/replicate-task.ts
import { task, wait } from "@trigger.dev/sdk";
import Replicate from "replicate";

const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN });

export const replicateTask = task({
  id: "replicate-prediction",
  run: async (payload: { prompt: string }) => {
    const token = await wait.createToken({
      timeout: "10m",
      tags: ["replicate"],
    });

    // Pass the token URL as the webhook — Replicate will POST results to it
    await replicate.predictions.create({
      version: "27b93a2413e7f36cd83da926f3656280b2931564ff050bf9575f1fdf9bcd7478",
      input: {
        prompt: payload.prompt,
      },
      webhook: token.url,
      webhook_events_filter: ["completed"],
    });

    // Pause until Replicate posts the result back
    const prediction = await wait.forToken(token).unwrap();
    return prediction;
  },
});

Managing tokens

import { wait } from "@trigger.dev/sdk";

// Retrieve a token
const token = await wait.retrieveToken(tokenId);

// List tokens (supports async iteration)
for await (const token of wait.listTokens()) {
  console.log("Token ID:", token.id);
}

// Complete a token
await wait.completeToken(tokenId, { result: "approved" });

Lifecycle hooks during waits

Use onWait and onResume hooks to run code when a task pauses or resumes. This is useful for managing resources like database connections:
/trigger/db-task.ts
import { task, wait } from "@trigger.dev/sdk";

export const dbTask = task({
  id: "db-task",
  onWait: async () => {
    // Release the database connection when pausing
    await db.disconnect();
  },
  onResume: async () => {
    // Reconnect when resuming
    await db.connect();
  },
  run: async (payload: any) => {
    await db.connect();

    // Do some work...

    // The task checkpoints here, releasing its compute slot
    await wait.for({ hours: 1 });

    // Task resumes here after 1 hour
    await db.query("SELECT 1");
  },
});

Build docs developers (and LLMs) love