Trigger.dev pivoted hard between V1 and V2. The original product aimed to be a developer-first Zapier alternative. After months of user feedback, the team realized developers wanted durable execution for long-running workflows, not just event hooks. V2 repositions as a Temporal alternative for TypeScript developers who need workflow orchestration without adopting heavyweight infrastructure.
The architectural shift exposes a key question: how do you build reliable, multi-step agent workflows in TypeScript without managing worker pools, state checkpoints, or distributed queues yourself?
What Changed From V1 to V2
V1 focused on event-driven triggers. You connected external services, defined handlers, and ran code when events arrived. It worked for simple automations but fell apart when developers needed retries, long-running tasks, or state persistence across failures.
V2 introduces durable execution primitives:
- Task-based orchestration: Define tasks as TypeScript functions with automatic retry and state persistence.
- Managed execution: No separate worker infrastructure. Trigger.dev handles task distribution, scaling, and observability.
- Serverless-first: Tasks run in ephemeral environments with elastic scaling, not long-lived worker processes.
- TypeScript-native: No DSL, no YAML, no code generation. Just async functions with decorators.
The shift targets teams building AI agents, media pipelines, or background jobs who want Temporal-style guarantees without Temporal-style complexity.
Durable Execution Model
Trigger.dev persists workflow state at task boundaries. When a task completes, the platform checkpoints its output. If a subsequent task fails, the workflow resumes from the last successful checkpoint instead of restarting from scratch.
This differs from Temporal’s event sourcing model. Temporal replays the entire workflow history to reconstruct state. Trigger.dev snapshots state at explicit points, reducing replay overhead but requiring developers to structure tasks with clear boundaries.
How State Persistence Works
Each task returns a serializable value. Trigger.dev stores that value in a managed database. When the next task starts, it receives the previous task’s output as input. If the task crashes, the platform retries from the last checkpoint.
export const processVideo = task({
id: "process-video",
run: async ({ videoUrl }: { videoUrl: string }) => {
// Step 1: Download (checkpointed on completion)
const localPath = await downloadVideo(videoUrl);
// Step 2: Transcode (checkpointed on completion)
const transcodedPath = await transcodeVideo(localPath);
// Step 3: Upload (checkpointed on completion)
const cdnUrl = await uploadToCDN(transcodedPath);
return { cdnUrl };
},
});
If transcodeVideo fails, the workflow retries from that step. It does not re-download the video. The platform knows downloadVideo completed because it checkpointed localPath.
Retry Semantics
Trigger.dev retries tasks with exponential backoff by default. You configure max attempts, backoff multipliers, and timeout thresholds per task. The platform handles retry scheduling, so you do not need to manage retry queues or dead-letter topics.
Idempotency is your responsibility. The platform guarantees at-least-once execution, not exactly-once. If your task has side effects (API calls, database writes), you must handle duplicate executions.
Serverless Execution vs Worker Pools
Temporal requires you to run worker processes that poll for tasks. Workers maintain long-lived connections to the Temporal server and execute workflow code in-process. You manage scaling, deployment, and resource allocation.
Trigger.dev abstracts execution into a managed service. You deploy task definitions to the platform. When a task triggers, Trigger.dev spins up an ephemeral container, executes the task, checkpoints state, and tears down the container. You do not manage workers.
| Dimension | Temporal | Trigger.dev |
|---|---|---|
| Execution model | Long-lived worker processes | Ephemeral serverless containers |
| Scaling | Manual worker pool sizing | Automatic elastic scaling |
| State persistence | Event sourcing with replay | Checkpoint snapshots at task boundaries |
| Deployment | Self-hosted or Temporal Cloud | Fully managed service |
| Cold start overhead | None (workers always running) | Container spin-up latency |
| Cost model | Fixed worker capacity | Pay-per-execution |
The serverless model trades cold start latency for operational simplicity. If your tasks run frequently, worker pools amortize startup costs. If your tasks are bursty or infrequent, serverless avoids idle capacity.
TypeScript SDK and Task Definition
Trigger.dev uses a decorator-based API. You define tasks as async functions wrapped in a task() call. The platform infers types from your function signature and handles serialization.
import { task } from "@trigger.dev/sdk/v3";
export const researchAgent = task({
id: "research-agent",
run: async ({ topic }: { topic: string }) => {
const messages: CoreMessage[] = [
{ role: "user", content: `Research: ${topic}` },
];
for (let i = 0; i < 10; i++) {
const { text, toolCalls, steps } = await generateText({
model: anthropic("claude-opus-4-20250514"),
system: "You are a research assistant with web access.",
messages,
tools: { search, browse, analyze },
maxSteps: 5,
});
if (!toolCalls.length) {
return { summary: text, stepsUsed: steps.length };
}
for (const call of toolCalls) {
const result = await executeTool(call);
messages.push({ role: "tool", content: result });
}
}
},
});
The SDK handles task registration, input validation, and result serialization. You do not write workflow DSLs or manage task queues manually. The platform infers dependencies from function calls and schedules tasks accordingly.
Triggering Tasks
Tasks trigger via HTTP API, SDK calls, or scheduled cron expressions. You do not poll for work. The platform pushes tasks to execution environments when they are ready.
// Trigger from application code
await researchAgent.trigger({ topic: "quantum computing" });
// Trigger from another task
export const orchestrator = task({
id: "orchestrator",
run: async () => {
const result = await researchAgent.triggerAndWait({ topic: "AI safety" });
return result;
},
});
triggerAndWait blocks until the child task completes, enabling sequential workflows. trigger returns immediately, enabling parallel fan-out.
Observability and Debugging
Trigger.dev provides a web UI for inspecting task executions. You can view:
- Task status (pending, running, completed, failed)
- Input and output payloads
- Retry attempts and backoff intervals
- Execution logs and stack traces
- Dependency graphs for multi-task workflows
The platform traces task execution across retries. If a task fails three times, you see logs from all three attempts, not just the final failure. This helps debug transient errors (rate limits, network timeouts) versus persistent bugs (logic errors, invalid input).
You cannot replay failed tasks from the UI. Trigger.dev does not support Temporal-style deterministic replay. If a task fails, you fix the code and re-trigger manually.
Deployment and Hosting
Trigger.dev offers a managed cloud service and self-hosted deployment. The cloud service handles execution infrastructure, scaling, and observability. You deploy task code via CLI or CI/CD pipelines.
Self-hosting requires running the Trigger.dev control plane (task scheduler, state store, API server) and execution workers (container runtime for tasks). The team provides Docker Compose and Kubernetes manifests, but you manage scaling and availability.
The managed service is simpler but locks you into Trigger.dev’s pricing and SLA. Self-hosting gives you control but requires operational expertise.
Failure Modes and Edge Cases
Long-Running Tasks and Timeouts
Trigger.dev supports tasks that run for hours or days. The platform does not impose hard timeouts, but you configure max execution time per task. If a task exceeds its timeout, the platform terminates it and retries.
Long-running tasks increase checkpoint overhead. If your task runs for six hours and checkpoints every 10 minutes, you accumulate 36 state snapshots. The platform stores these in a managed database, so storage costs scale with checkpoint frequency.
Concurrency and Rate Limiting
Trigger.dev supports concurrency controls. You define max concurrent executions per task or per workflow. The platform queues excess tasks until capacity frees up.
This helps when calling rate-limited APIs. If your task calls an API with a 10 requests/second limit, you set max concurrency to 10. The platform throttles task execution to stay within the limit.
State Size Limits
Checkpointed state must fit in the platform’s database. Trigger.dev does not publish hard limits, but large payloads (multi-GB files, large datasets) will hit storage or serialization constraints. You should store large artifacts in external storage (S3, R2) and checkpoint references, not raw data.
Technical Verdict
Trigger.dev V2 is the right choice when you need durable TypeScript workflows without infrastructure overhead. The checkpoint model and serverless execution eliminate operational complexity at the cost of replay flexibility.
Use Trigger.dev if:
- Your tasks are bursty or scheduled (nightly jobs, webhook handlers, agent workflows). Serverless avoids paying for idle worker capacity between executions.
- You write TypeScript and want native async/await orchestration without learning a workflow DSL or managing polyglot runtimes.
- You need built-in observability (execution traces, retry logs, dependency graphs) without deploying Jaeger, Grafana, or custom tracing infrastructure.
- Your workflows have clear task boundaries. The checkpoint model works best when each step produces a discrete, serializable output (API response, file path, database ID).
Avoid Trigger.dev if:
- Your tasks run continuously or at high frequency (real-time data processing, sub-second latency requirements). Worker pools amortize cold start overhead better than ephemeral containers.
- You need deterministic replay for debugging, compliance, or auditing. Trigger.dev checkpoints state but does not replay execution history like Temporal.
- You require multi-language support. Temporal runs workflows in Go, Java, Python, and PHP. Trigger.dev is TypeScript-only.
- You need fine-grained control over execution environments (custom container images, GPU workers, on-premises deployment with air-gapped networks). The managed service abstracts infrastructure, which limits configurability.
The platform optimizes for developer velocity over operational flexibility. If you value shipping workflows quickly over tuning every execution parameter, Trigger.dev delivers. If you need the control to run workflows in custom runtimes or replay execution for compliance, Temporal remains the better choice.