Trigger.dev launched in February 2023 as a “developer-first Zapier alternative” and pulled 745 points on Hacker News. Eight months later, the team shipped V2 and repositioned as a “Temporal alternative for TypeScript.”
That pivot exposes a real infrastructure gap: developers want durable execution without standing up a JVM cluster, learning gRPC service definitions, or reasoning about event sourcing history replay. The shift from event triggers to durable workflows is not cosmetic. It reflects user feedback that the hard problem is not connecting APIs but managing long-running tasks that survive process crashes, retries, and partial failures. As one HN commenter noted, “We tried building this ourselves and gave up after the third time our job queue ate a task during a deploy.”
Trigger.dev V2 tackles this with TypeScript-native primitives, a managed execution layer, and deployment ergonomics that skip the operational overhead of Temporal’s worker processes and history databases.
What Durable Execution Actually Means
Durable execution guarantees that a workflow completes even if the process dies mid-run. The system must:
- Persist execution state at every step boundary
- Replay or resume from the last checkpoint after a crash
- Handle retries with idempotency so duplicate work does not corrupt state
- Isolate long-running tasks from request-response timeouts
Temporal achieves this with event sourcing: every workflow decision is logged as an event, and replay reconstructs state by re-executing deterministic code against the event log. This works but requires developers to avoid non-deterministic operations (random numbers, wall-clock time, external I/O) inside workflow code. Temporal enforces this with a strict separation between workflows (deterministic orchestration) and activities (side effects).
Trigger.dev takes a different approach. Instead of replaying history, it checkpoints state at task boundaries and resumes from the last successful step. This trades replay flexibility for simpler mental models: you write normal TypeScript async functions, and the runtime handles persistence.
State Persistence Model
Based on public documentation and repository inspection, Trigger.dev appears to use a hybrid checkpoint-and-resume model:
- Each task is a unit of work with explicit boundaries
- State is serialized to Postgres after each task completes
- On failure, the system resumes from the last checkpoint, not from the beginning
- Retries are automatic with exponential backoff
This avoids Temporal’s event log growth problem. A workflow with 10,000 steps in Temporal can generate up to 10,000 events in the history database. Trigger.dev stores only the current state snapshot and metadata about completed tasks.
The trade: you cannot time-travel through execution history or replay arbitrary points in the workflow. For workflows that process uploads, call third-party APIs, or send notifications after delays, this is acceptable. For complex sagas with compensation logic, Temporal’s replay model gives finer control.
Retry Semantics and Idempotency
Trigger.dev handles retries at the task level, not the function level. Each task declaration includes retry configuration:
export const processUpload = task({
id: "process-upload",
retry: {
maxAttempts: 3,
factor: 2,
minTimeout: 1000,
maxTimeout: 10000,
},
run: async (payload: { fileUrl: string }) => {
const file = await downloadFile(payload.fileUrl);
const result = await analyzeImage(file);
await saveToDatabase(result);
return result;
},
});
If analyzeImage throws, the entire task retries. The runtime does not automatically deduplicate side effects, so you must ensure downloadFile and saveToDatabase are idempotent or use explicit guards.
Temporal enforces idempotency through activity IDs: the same activity invoked twice with the same ID returns the cached result. Trigger.dev leaves this to the developer, which is simpler for small workflows but riskier for complex orchestrations.
Isolation and Scheduling
Trigger.dev runs tasks in isolated Node.js processes, not in-process workers. Each task execution spawns a separate container in the managed environment. This provides:
- Memory isolation: one task cannot OOM another
- CPU fairness: long-running tasks do not starve the queue
- Crash isolation: a segfault in one task does not kill the scheduler
The deployment model is fully managed. You push code to Trigger.dev’s platform, and it handles container orchestration, autoscaling, and log aggregation. This is the opposite of Temporal, where you run your own worker fleet and manage scaling, health checks, and graceful shutdowns.
For self-hosting, Trigger.dev provides Docker images and Kubernetes manifests. The architecture is simpler than Temporal: a single API server, a Postgres database, and worker containers. No separate history service, matching service, or frontend service.
Concurrency and Queues
Trigger.dev exposes concurrency controls at the task and queue level:
| Control | Scope | Behavior |
|---|---|---|
maxConcurrency | Task | Limits parallel executions of the same task |
queue | Logical group | Groups tasks into named queues with independent concurrency |
rateLimit | Task or queue | Throttles executions per time window |
This is coarser than Temporal’s worker tuning (pollers per task queue, max concurrent activities, max concurrent workflow tasks) but easier to reason about. Most developers do not need fine-grained control over poller threads.
Example queue configuration:
// Example from Trigger.dev documentation
export const emailQueue = queue({
name: "email-processing",
concurrency: 10,
rateLimit: {
limit: 100,
window: "1m",
},
});
export const sendEmail = task({
id: "send-email",
queue: emailQueue,
run: async (payload: { to: string; body: string }) => {
await emailProvider.send(payload);
},
});
Observability
Trigger.dev ships with built-in tracing and logs. Each task execution generates:
- A trace ID linking all steps in the workflow
- Structured logs with automatic context injection
- Metrics on duration, retry count, and failure rate
The dashboard shows real-time execution graphs, similar to Temporal’s Web UI. You can drill into individual runs, inspect payloads, and replay failed tasks.
The difference: Trigger.dev’s observability is opinionated and bundled. Temporal requires you to configure OpenTelemetry exporters, set up Prometheus scrapers, and wire Grafana dashboards. For teams without dedicated SRE capacity, Trigger.dev’s batteries-included approach is faster.
Failure Modes
Trigger.dev’s checkpoint model has specific failure characteristics. If a task crashes between checkpoints, work since the last checkpoint is lost. Temporal’s event log captures every decision, so replay is exact. Large state objects (multi-MB payloads) slow down serialization in Trigger.dev. Temporal’s history can grow unbounded, but Trigger.dev encourages storing large data externally and passing references. Unlike Temporal, Trigger.dev does not enforce deterministic replay, so bugs involving random IDs or timestamps can cause inconsistent retries.
For workflows that require strict auditability or complex compensation, Temporal’s guarantees are stronger. For background jobs that tolerate occasional re-execution, Trigger.dev’s simplicity wins.
Deployment Shape
Trigger.dev’s managed platform handles:
- Container orchestration (no Kubernetes required)
- Autoscaling based on queue depth
- Log aggregation and retention
- Secret management
Self-hosted deployments require:
- Postgres 14+ for state and metadata
- Redis for task queuing (optional but recommended)
- Docker or Kubernetes for worker containers
- Object storage (S3, GCS) for large payloads
Temporal’s self-hosted footprint is heavier: Cassandra or MySQL for history, Elasticsearch for visibility, multiple service types (frontend, matching, history, worker), and careful tuning of retention policies to avoid database bloat.
When to Use Trigger.dev
Choose Trigger.dev when:
- Your team writes TypeScript and wants to avoid JVM tooling
- Workflows are mostly linear (call API, transform data, store result)
- You need fast deployment without managing worker infrastructure
- Observability and retries are more important than strict event sourcing
Avoid Trigger.dev when:
- You need complex sagas with compensation logic
- Workflows require strict auditability and time-travel debugging
- You already run Temporal and have invested in worker tuning
- You need multi-language support (Temporal supports Go, Java, Python, PHP)
Technical Verdict
Trigger.dev V2 is a pragmatic durable execution layer for TypeScript teams that want Temporal’s guarantees without its operational complexity. The checkpoint-and-resume model trades replay precision for deployment simplicity. For AI agents, media processing, and long-running background jobs, this is the right choice. For financial workflows or systems requiring strict auditability, Temporal’s event sourcing remains the safer option.
The pivot from “Zapier alternative” to “Temporal alternative” is honest. The hard problem is not connecting APIs but managing state, retries, and failures in long-running processes. Trigger.dev solves this for the 80% case where TypeScript ergonomics and managed infrastructure matter more than event log perfection.