Background jobs are inevitable the moment your AI app needs to do anything that takes longer than a few seconds — sending emails, processing uploads, calling slow APIs, or running LLM chains. Trigger.dev is an open-source background jobs platform built specifically for TypeScript developers. You write each job as a plain TypeScript task, deploy it to Trigger.dev, and trigger it from your app — then watch every run in a real-time dashboard with automatic retries, durable waits, and full logs, without managing queues, workers, or Redis yourself.
This guide walks through integrating Trigger.dev v4 into a Next.js application from scratch, including local development with the CLI, writing your first task, and triggering it from an API route.
How Trigger.dev Works
In v4 you write your tasks in a dedicated trigger/ directory and deploy them to Trigger.dev with a single CLI command. Trigger.dev bundles your task code into a container and runs each task on its own managed infrastructure — or on your self-hosted instance. Your Next.js app never executes the job itself; it simply fires the task through the SDK, and Trigger.dev handles queuing, execution, retries, and durability. Every run is checkpointed, so a task can wait for hours or days without holding a server open.
| Concept | Description |
|---|---|
| Task | A TypeScript function defined with task() and exported from a file in your trigger/ directory |
| Payload | The JSON object you pass when triggering a task |
| Run | A single execution of a task with a given payload |
| Deploy | Bundling your tasks into a new version on Trigger.dev with npx trigger.dev deploy so they can run in production |
Installation
# Install the SDK npm install @trigger.dev/sdk # Log in and initialize Trigger.dev in your project # (creates trigger.config.ts and a trigger/ directory with an example task) npx trigger.dev@latest login npx trigger.dev@latest init
The init command creates a trigger/ directory (with an example task) and a trigger.config.ts file at your project root, and stores your project reference. There is no API route to wire up: in v4 your tasks are deployed to Trigger.dev and run on its infrastructure, so nothing needs to be mounted inside your Next.js app.
Writing Your First Task
// trigger/send-welcome-email.ts import { task, logger } from "@trigger.dev/sdk"; export const sendWelcomeEmail = task({ id: "send-welcome-email", // Retry a few times if the email provider is flaky retry: { maxAttempts: 3, factor: 2, minTimeoutInMs: 1000, maxTimeoutInMs: 10000, }, run: async ( payload: { userId: string; email: string; name: string }, { ctx } ) => { // logger sends structured logs to the Trigger.dev dashboard logger.info("Sending welcome email", { email: payload.email }); // Replace with your email provider (Resend, SendGrid, etc.) const response = await fetch("https://api.resend.com/emails", { method: "POST", headers: { Authorization: `Bearer ${process.env.RESEND_API_KEY}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: "hello@yourapp.com", to: payload.email, subject: `Welcome, ${payload.name}!`, html: `<p>Thanks for signing up. We're glad you're here.</p>`, }), }); if (!response.ok) { // Throwing marks the run as failed and triggers a retry throw new Error(`Resend returned ${response.status}`); } const result = await response.json(); logger.info("Email sent", { id: result.id }); return { success: true, emailId: result.id }; }, });
Configuring the Project
Trigger.dev automatically discovers every task exported from the directories listed in your config — there is no manual registry or index file to maintain. The trigger.config.ts file at your project root holds your project reference and any defaults, such as a global retry policy or a maximum run duration:
// trigger.config.ts import { defineConfig } from "@trigger.dev/sdk"; export default defineConfig({ project: "proj_your_project_ref", // from your Trigger.dev dashboard dirs: ["./trigger"], // where your task files live maxDuration: 60, // default per-run timeout (seconds) retries: { enabledInDev: false, // don't retry while developing locally default: { maxAttempts: 3, factor: 2, minTimeoutInMs: 1000, maxTimeoutInMs: 10000, randomize: true, }, }, });
Triggering a Task from Your App
// app/api/auth/signup/route.ts import { tasks } from "@trigger.dev/sdk"; import type { sendWelcomeEmail } from "@/trigger/send-welcome-email"; import { NextResponse } from "next/server"; export async function POST(req: Request) { const { email, name } = await req.json(); // Create the user in your database... const user = await createUser({ email, name }); // Fire-and-forget: trigger the task on Trigger.dev's infra. // The type-only import keeps full payload type-safety without // bundling your task code into the Next.js route. await tasks.trigger<typeof sendWelcomeEmail>("send-welcome-email", { userId: user.id, email: user.email, name: user.name, }); return NextResponse.json({ userId: user.id }, { status: 201 }); }
Local Development
# In one terminal — run your Next.js app npm run dev # In another terminal — start the Trigger.dev dev server npx trigger.dev@latest dev # The CLI runs your tasks locally and streams each run # to the dashboard in real time
Use wait.for({ days: 3 }) inside a task to pause for a duration without holding a worker. Trigger.dev checkpoints the run and resumes it later — perfect for delayed follow-ups such as a reminder email three days after signup.Environment Variables
# .env.local TRIGGER_SECRET_KEY=tr_dev_xxxxxxxxxxxxxxxxxxxx # Optional — point at a self-hosted instance: # TRIGGER_API_URL=https://your-trigger-server.com
Viewing Runs in the Dashboard
Every run appears in the Trigger.dev dashboard with full logs, timings, input/output payloads, and retry history. You can replay a failed run with its original payload — no need to re-trigger it from your app. This makes debugging background jobs dramatically faster than tailing application logs.
Next Steps
- Add scheduled tasks with schedules.task({ cron }) for periodic work
- Chain tasks together with triggerAndWait() and batchTriggerAndWait()
- Call any Node SDK directly inside a task — Resend, OpenAI, Stripe, GitHub, and more
- Ship to production with npx trigger.dev@latest deploy, or self-host the whole platform