Trigger.dev launched in February 2023 as a “developer-first Zapier alternative” and earned 745 points on Hacker News. Eight months later, the team shipped V2 and repositioned as a “Temporal alternative for TypeScript.” That pivot exposes the architectural gap between event-driven automation and durable execution engines.
The shift matters because Temporal’s Go-based runtime creates friction for TypeScript teams. You write workflows in TypeScript, but the orchestration layer runs in Go. Trigger.dev collapses that boundary by running everything in Node.js (now Bun). The trade-off is not just language preference. It is about how state snapshots, retry semantics, and execution isolation work when your orchestration engine and your task code share a runtime.
What Changed Between V1 and V2
V1 focused on event triggers. You connected webhooks, scheduled cron jobs, and chained tasks. The mental model was Zapier with code. V2 dropped the event-trigger framing and adopted durable execution primitives: long-running tasks, automatic retries, queues, and state persistence.
The user feedback loop was clear. Developers wanted to write background jobs that survive crashes, not wire up event flows. They needed retry logic that did not require custom error handling. They wanted observability without instrumenting every function.
V2’s task API looks like this:
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 task wraps a standard async function. Trigger.dev intercepts execution, snapshots state at checkpoints, and replays from the last checkpoint on failure. You do not write workflow DSL. You write TypeScript.
State Persistence and Replay Mechanics
Temporal uses event sourcing. Every workflow decision generates an event. The workflow state is the sum of those events. Replay means re-executing the workflow code with the same event sequence. Side effects (API calls, database writes) are deterministic because the runtime memoizes them.
Trigger.dev snapshots task state at explicit checkpoints. When a task calls an external API or waits for a timer, the platform records the result. On retry, the task resumes from the last checkpoint without re-executing prior steps. This is closer to Inngest’s approach than Temporal’s.
The difference shows up in debugging. Temporal lets you replay a workflow with different code to test fixes. Trigger.dev’s checkpoint model means you cannot change the code path mid-execution. You can retry from the last checkpoint, but the logic before that checkpoint is frozen.
| Feature | Temporal | Trigger.dev V2 |
|---|---|---|
| State model | Event sourcing | Checkpoint snapshots |
| Replay semantics | Full workflow re-execution | Resume from last checkpoint |
| Side effect handling | Deterministic replay with memoization | Explicit checkpoint capture |
| Code versioning | Supports mid-flight code changes | Requires task completion before update |
| Language runtime | Go orchestrator, polyglot workers | TypeScript/Bun end-to-end |
Retry and Timeout Semantics
Trigger.dev exposes retry configuration at the task level. You set max attempts, backoff strategy, and timeout per task. The platform handles retries automatically. If a task throws an exception, the runtime snapshots the error, waits for the backoff interval, and re-runs from the last checkpoint.
Timeouts are per-task, not per-step. If your task runs for two hours and times out, you lose progress since the last checkpoint. Temporal’s activity timeouts are more granular. You can set start-to-close, schedule-to-start, and heartbeat timeouts independently.
Trigger.dev’s simpler model works well for tasks that checkpoint frequently. If your task makes ten API calls and checkpoints after each, a timeout only loses the current call. If your task runs a long computation without checkpoints, a timeout is expensive.
Execution Isolation and Deployment Shape
Trigger.dev runs tasks in isolated containers. Each task execution gets a fresh container with a defined resource limit (CPU, memory). The platform manages container lifecycle, scaling up when queue depth increases and scaling down during idle periods.
This is different from Temporal’s worker model. Temporal workers are long-lived processes that poll for tasks. You deploy workers as Kubernetes pods, ECS tasks, or VM instances. Scaling means adding more workers. Temporal does not manage the worker infrastructure.
Trigger.dev’s managed container model reduces operational overhead but introduces cold start latency. The first invocation of a task after idle time waits for container spin-up. Temporal workers stay warm, so task latency is lower.
The trade-off table:
| Concern | Temporal Workers | Trigger.dev Containers |
|---|---|---|
| Cold start latency | None (workers stay warm) | 1-3 seconds on first invocation |
| Scaling control | Manual (deploy more workers) | Automatic (platform-managed) |
| Resource isolation | Shared worker process | Dedicated container per task |
| Cost model | Pay for worker uptime | Pay for task execution time |
| Operational burden | High (manage worker fleet) | Low (platform handles infrastructure) |
Observability and Debugging Surface
Trigger.dev includes built-in tracing. Every task execution generates a trace with step-level timing, input/output snapshots, and error details. The dashboard shows task history, retry attempts, and queue depth.
Temporal’s observability is more granular but requires more setup. You get workflow history, activity timelines, and event logs. Temporal Cloud includes dashboards, but self-hosted deployments need custom instrumentation.
Trigger.dev’s advantage is zero-config observability. You write a task, deploy it, and the platform captures execution details. The disadvantage is limited customization. You cannot add custom metrics or integrate with external tracing systems easily.
When the TypeScript-Native Model Breaks Down
Trigger.dev’s TypeScript-only runtime limits interoperability. If you need to call Python ML models or Rust data pipelines, you must wrap them in HTTP APIs or spawn subprocesses. Temporal’s polyglot worker model lets you run Python activities alongside TypeScript workflows.
The checkpoint model also struggles with non-deterministic code. If your task reads the current timestamp or generates random numbers, replays produce different results. Temporal enforces determinism through its workflow API. Trigger.dev trusts you to avoid non-deterministic operations between checkpoints.
Finally, Trigger.dev’s managed infrastructure means you cannot self-host the orchestration layer easily. The open-source repo includes the task SDK, but the execution engine is closed. Temporal is fully open-source, so you can run the entire stack on your own infrastructure.
Technical Verdict
Use Trigger.dev when you need durable background jobs in TypeScript and want to avoid managing worker infrastructure. It works well for AI agent loops, media processing pipelines, and scheduled data syncs. The checkpoint model is simple, the observability is built-in, and the deployment is one command.
Avoid Trigger.dev if you need polyglot workflows, sub-second task latency, or full control over the orchestration layer. Temporal’s event sourcing model is more flexible for complex workflows with branching logic and mid-flight code updates. The operational cost is higher, but the runtime guarantees are stronger.
The pivot from event triggers to durable execution reveals a broader pattern. Developers want orchestration primitives that feel like writing normal code, not workflow DSL. Trigger.dev’s bet is that TypeScript-native execution and managed infrastructure are worth the trade-offs in flexibility and control. For teams building AI agents and background jobs in TypeScript, that bet is paying off.