Skip to main content

Background Tasks

Async

Define durable background tasks, trigger them from anywhere, and schedule recurring cron jobs.

Immediate Tasks

Run tasks in background

Delayed Tasks

Schedule for later

Cron Tasks

Recurring schedules

Auto Retry

Exponential backoff

Overview

The Tasks SDK lets you define typed background tasks and trigger them asynchronously. Perfect for sending emails, processing data, generating reports, or any work that shouldn't block your main request. Tasks support durable steps, automatic retries, cron scheduling, and full type safety.

Define a Task

Define a task with task() and expose it via a route handler using serve():

app/tasks/send-email.ts
import { task } from '@sylphx/sdk/tasks'
import { mailer } from '@/lib/mailer'

export const sendEmail = task({
  id: 'send-email',
  run: async ({ to, template }: { to: string; template: string }) => {
    await mailer.send({ to, template })
    return { sent: true }
  },
})
app/api/tasks/route.ts
import { serve } from '@sylphx/sdk/tasks'
import { sendEmail } from '@/tasks/send-email'

// Expose GET (health) and POST (dispatch) handlers
export const { GET, POST } = serve({ tasks: [sendEmail] })

Trigger a Task

Trigger a task from any server-side code — fully type-safe:

import { sendEmail } from '@/tasks/send-email'

// Fire-and-forget — returns immediately with a RunHandle
const handle = await sendEmail.trigger({
  to: user.email,
  template: 'welcome',
})

console.log(handle.id) // Task run ID for tracking

// Delayed trigger — run after 1 hour
await sendEmail.trigger(
  { to: user.email, template: 'follow-up' },
  { delay: '1h' },
)

Wait for a Result

Use triggerAndWait to dispatch and block until the task completes:

import { sendEmail } from '@/tasks/send-email'

// Dispatch and wait for the result (type-safe)
const result = await sendEmail.triggerAndWait({
  to: user.email,
  template: 'welcome',
})

console.log(result.sent) // true

Durable Steps

Use step.run() and step.sleep() to make your task durable — steps are cached on completion and replayed instantly on retry:

import { task } from '@sylphx/sdk/tasks'

export const sendEmail = task({
  id: 'send-email',
  run: async ({ to, subject }, { step }) => {
    // Each step is cached — safe to retry
    const validated = await step.run('validate', () => validateEmail(to))
    await step.sleep('cooldown', '1 minute')
    return step.run('send', () => mailer.send(validated, subject))
  },
})

Recurring Tasks (Cron)

Schedule recurring tasks with cron expressions:

import { createCron } from '@sylphx/sdk/tasks'

const config = {
  secretKey: process.env.SYLPHX_SECRET_KEY!,
  ref: process.env.SYLPHX_PROJECT_REF!,
}

// Run every day at 9am UTC
await createCron(config, {
  name: 'daily-report',
  cron: '0 9 * * *',
  callbackUrl: 'https://myapp.com/api/tasks',
  payload: { type: 'daily' },
})

// Run every hour
await createCron(config, {
  name: 'hourly-cleanup',
  cron: '0 * * * *',
  callbackUrl: 'https://myapp.com/api/tasks',
})
PropertyTypeDescription
* * * * *patternEvery minute
0 * * * *patternEvery hour
0 0 * * *patternEvery day at midnight
0 9 * * 1-5patternWeekdays at 9am
0 0 1 * *patternFirst of every month

Task Status

Check the status of a triggered task:

import { getTask } from '@sylphx/sdk/tasks'

const config = {
  secretKey: process.env.SYLPHX_SECRET_KEY!,
  ref: process.env.SYLPHX_PROJECT_REF!,
}

const status = await getTask(config, taskRunId)

console.log(status)
// {
//   id: 'run_abc123',
//   status: 'completed', // 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'
//   createdAt: '2024-01-15T10:00:00Z',
//   startedAt: '2024-01-15T10:00:01Z',
//   completedAt: '2024-01-15T10:00:05Z',
//   result: { sent: true },
// }

Cancel Tasks

Cancel a pending task:

import { cancelTask } from '@sylphx/sdk/tasks'

const config = {
  secretKey: process.env.SYLPHX_SECRET_KEY!,
  ref: process.env.SYLPHX_PROJECT_REF!,
}

// Cancel a specific task run
await cancelTask(config, taskRunId)

Retries

Configure automatic retries for failed tasks:

import { task } from '@sylphx/sdk/tasks'

export const processOrder = task({
  id: 'process-order',
  retry: {
    maxAttempts: 3,
    backoff: 'exponential',
  },
  run: async ({ orderId }) => {
    await chargeAndFulfill(orderId)
  },
})

Retry Behavior

Tasks are retried automatically on failure. Use step.run() inside your task to make individual steps durable — completed steps are not re-executed on retry.

Batch Trigger

Dispatch multiple runs in parallel:

import { sendEmail } from '@/tasks/send-email'

// Dispatch N runs in parallel
const batch = await sendEmail.batchTrigger([
  { to: '[email protected]', template: 'welcome' },
  { to: '[email protected]', template: 'welcome' },
  { to: '[email protected]', template: 'welcome' },
])

// Wait for all to complete
const results = await Promise.all(batch.runs.map(h => h.waitForCompletion()))

Common Use Cases

Email sending

Queue emails instead of blocking requests

Data processing

Process uploads in the background

Report generation

Generate PDFs or exports async

Webhooks

Reliable webhook delivery with retries

Scheduled tasks

Daily cleanups, weekly reports

Notifications

Send notifications without blocking