Skip to content

Scheduled Tasks (Cron)

Scheduled tasks run on a recurring schedule defined by a cron expression. For one-off future triggers, use the delay option instead.

Defining a Scheduled Task

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

export const firstScheduledTask = schedules.task({
  id: "first-scheduled-task",
  run: async (payload) => {
    console.log(payload.timestamp);    // Date — when task was scheduled to run
    console.log(payload.lastTimestamp); // Date or undefined — when last run
    console.log(payload.timezone);     // IANA format, e.g. "America/New_York"
    console.log(payload.scheduleId);   // string — the schedule id
    console.log(payload.externalId);   // string or undefined
    console.log(payload.upcoming);     // Date[] — next 5 scheduled dates
  },
});

WARNING

This task will NOT trigger on a schedule until you attach a schedule to it.

Attaching a Schedule

Two approaches:

MethodDefined whereSynced when
DeclarativeOn the schedules.taskOn dev or deploy
ImperativeDashboard or SDKAt runtime

Declarative Schedule

ts
export const firstScheduledTask = schedules.task({
  id: "first-scheduled-task",
  cron: "0 */2 * * *", // every 2 hours (UTC)
  run: async (payload) => { /* ... */ },
});

With timezone and environment targeting:

ts
export const secondScheduledTask = schedules.task({
  id: "second-scheduled-task",
  cron: {
    pattern: "0 5 * * *",          // 5am daily
    timezone: "Asia/Tokyo",
    environments: ["PRODUCTION", "STAGING"],
  },
  run: async (payload) => { /* ... */ },
});

Imperative Schedule

ts
const createdSchedule = await schedules.create({
  task: firstScheduledTask.id,
  cron: "0 0 * * *",
  timezone: "America/New_York",
  externalId: "user_123456",          // for multi-tenant schedules
  deduplicationKey: "user_123456-reminder",
});

Cron Syntax Reference

*    *    *    *    *
│    │    │    │    └── day of week (0-7, 1L-7L; 0 or 7 = Sunday)
│    │    │    └─────── month (1-12)
│    │    └──────────── day of month (1-31, L)
│    └───────────────── hour (0-23)
└────────────────────── minute (0-59)
  • L means "last" (e.g., L in day-of-month = last day of month)
  • Seconds are not supported

When Schedules Won't Trigger

  • Dev environment — only triggers when the CLI dev server is running
  • Staging/Production — only triggers if the task is in the current deployment (latest version)

Dynamic / Multi-Tenant Schedules

Use externalId to create per-user schedules:

ts
export const reminderTask = schedules.task({
  id: "todo-reminder",
  run: async (payload) => {
    if (!payload.externalId) throw new Error("externalId required");
    const user = await db.getUser(payload.externalId);
    await sendReminderEmail(user);
  },
});

// Create schedule per user
await schedules.create({
  task: "todo-reminder",
  cron: "0 9 * * 1", // 9am every Monday
  externalId: userId,
  deduplicationKey: `reminder-${userId}`,
});

Always use deduplicationKey

When creating schedules dynamically, always include a deduplicationKey to prevent duplicates.

SDK Management Functions

ts
await schedules.retrieve(scheduleId)  // Get a schedule
await schedules.list()                // List all schedules
await schedules.update(scheduleId, options)  // Update schedule
await schedules.deactivate(scheduleId)       // Pause schedule
await schedules.activate(scheduleId)         // Resume schedule
await schedules.del(scheduleId)              // Delete schedule
await schedules.timezones()                  // Get valid IANA timezones

Plan Limits

TierMax Schedules
Free10 per project
Hobby100 per project
Pro1,000+ per project

Extra bundles: $10/month per 1,000 schedules.

Built from official Trigger.dev documentation