Trigger.dev positions itself between Zapier’s GUI-based automation and Temporal’s heavyweight workflow engine. The platform lets developers define background tasks directly in TypeScript, then handles event routing, retries, and observability without forcing you into a visual builder or learning a new DSL. After pivoting from v1 (Zapier alternative) to v2 (Temporal alternative for TypeScript devs), the project gained traction (745 HN points, 190 comments) by solving a specific challenge: you want durable, long-running tasks but don’t want to deploy a Temporal cluster or wire up SQS + Lambda manually.
This article examines the plumbing: how Trigger.dev routes events to tasks, what its durability and retry model looks like, and where it fits in the orchestration landscape.
Core Architecture: Tasks as Decorated Functions
Trigger.dev uses a decorator-based model. You export a task function from your codebase, the platform discovers it, and you trigger it via webhook, schedule, or direct invocation.
import { task } from "@trigger.dev/sdk/v3";
export const processOrder = task({
id: "process-order",
run: async (payload: { orderId: string }) => {
const order = await db.orders.findUnique({ where: { id: payload.orderId } });
// Long-running steps with automatic checkpointing
await sendConfirmationEmail(order);
await chargePaymentProvider(order);
await updateInventory(order);
return { status: "completed", orderId: order.id };
},
});
Code example reflects v3 SDK patterns per official documentation.
Key architectural choices:
- No separate workflow definition language: Tasks are TypeScript functions. The platform instruments them at runtime.
- Automatic checkpointing: Each
awaitboundary can be a checkpoint. If the task crashes, it resumes from the last successful step. - Event ingestion: Trigger.dev exposes HTTP endpoints for each task. You POST JSON, it queues the execution.
This differs from Temporal, where you write workflows in a restricted subset of code (no non-deterministic operations, no direct I/O in workflow functions). Trigger.dev lets you write normal async code and handles durability behind the scenes.
Event Routing and Queue Mechanics
Trigger.dev’s event flow:
- Webhook ingestion: Each task gets a unique HTTPS endpoint. POST to it with JSON payload.
- Queue assignment: Tasks land in a Redis-backed queue (self-hosted) or managed queue (cloud).
- Worker pool: Workers poll the queue, execute the task function, and report back.
- State persistence: Task state (input, output, intermediate checkpoints) lives in Postgres.
Latency profile (typical observed ranges):
- Cold start: 200-500ms for first invocation (worker spin-up).
- Warm path: 10-50ms queue-to-execution.
- Checkpoint overhead: 5-20ms per
awaitboundary (writes to Postgres).
This is faster than Temporal for simple tasks (no gRPC overhead, no history replay) but slower than raw Lambda invocations (checkpointing adds latency). The trade-off is durability: if your task crashes mid-execution, Trigger.dev resumes from the last checkpoint instead of restarting from scratch.
Durability Model: Checkpoints vs. Event Sourcing
| Feature | Trigger.dev | Temporal | Zapier |
|---|---|---|---|
| State storage | Postgres snapshots at await | Event-sourced history | Proprietary task log |
| Replay mechanism | Resume from last checkpoint | Replay full workflow history | Retry entire step |
| Determinism requirement | None (normal async code) | Strict (no side effects in workflow) | N/A (GUI steps) |
| Observability | Checkpoint tree in UI | Full event history | Step-by-step log |
| Storage cost | Low (only checkpoints) | High (every decision logged) | Opaque |
Comparison based on public documentation and observed behavior as of 2025.
Trigger.dev’s checkpoint model is simpler than Temporal’s event sourcing but less granular. You can’t replay a task from an arbitrary point in time, only from the last successful checkpoint. For most background jobs (send email, call API, update database), this is sufficient. For complex sagas with compensating transactions, Temporal’s full history replay is more powerful.
Retry and Failure Handling
Trigger.dev exposes retry primitives at the task level:
export const flakyScraper = task({
id: "flakey-scraper",
retry: {
maxAttempts: 5,
factor: 2,
minTimeout: 1000,
maxTimeout: 60000,
},
run: async ({ url }: { url: string }) => {
const html = await fetch(url).then(r => r.text());
return parseHTML(html);
},
});
Retry behavior:
- Exponential backoff: Configurable factor and jitter.
- Per-step retries: If a checkpoint fails, only that step retries (not the entire task).
- Dead-letter queue: After max attempts, task moves to a DLQ for manual inspection.
Compared to Zapier:
- Zapier retries the entire step (no sub-step granularity).
- Trigger.dev retries from the last checkpoint (more efficient for multi-step tasks).
Compared to Temporal:
- Temporal retries are declarative in workflow code (same exponential backoff primitives).
- Temporal’s activity timeouts are more granular (start-to-close, schedule-to-start, heartbeat).
- Trigger.dev’s model is simpler but less flexible for complex timeout scenarios.
Secrets and Environment Isolation
Trigger.dev handles secrets via environment variables injected at runtime:
- Self-hosted: You manage secrets in your deployment (Kubernetes secrets, AWS Secrets Manager).
- Cloud: Secrets stored encrypted in Postgres, injected into worker containers at task execution.
Multi-tenancy model:
- Each project gets isolated worker pools.
- Secrets scoped per project (no cross-project leakage).
- No shared worker containers (unlike some FaaS platforms).
This is safer than Zapier’s shared execution environment but less isolated than Temporal’s namespace model (where each namespace can have separate worker fleets with different security boundaries).
Observability: What You See When Tasks Fail
Trigger.dev’s UI shows a checkpoint tree, which is a hierarchical view of task execution where each await boundary appears as a node with branches for retries and parallel operations. The interface also displays:
- Logs: Stdout/stderr from each task execution.
- Metrics: Duration, retry count, queue depth.
- Traces: OpenTelemetry-compatible spans (optional).
Key difference from Temporal:
- Temporal’s UI shows full event history (every decision, timer, signal).
- Trigger.dev shows checkpoint snapshots (less granular but easier to scan).
Key difference from Zapier:
- Zapier shows step-by-step logs (GUI-oriented).
- Trigger.dev shows code execution flow (developer-oriented).
For debugging, Trigger.dev’s checkpoint tree is useful for understanding where a task failed. For auditing, Temporal’s full history is more complete.
Deployment Shape: Self-Hosted vs. Cloud
Trigger.dev offers two deployment modes:
Self-hosted:
- Docker Compose or Kubernetes.
- Requires Postgres, Redis, and a worker runtime (Node.js or Bun).
- You manage scaling, backups, and monitoring.
Cloud:
- Managed Postgres and Redis.
- Elastic worker pools (scales to zero).
- Pay per task execution (similar to Lambda pricing).
Self-hosted gives you control but requires operational overhead. Cloud is simpler but locks you into Trigger.dev’s pricing model. For agentic systems with unpredictable workloads, the cloud’s elastic scaling is valuable. For high-volume, predictable tasks, self-hosted is cheaper.
Failure Modes and Operational Risks
Common failure scenarios:
- Checkpoint corruption: If Postgres write fails mid-checkpoint, task state may become inconsistent. This represents a potential risk where you may see duplicate side effects (e.g., double email send) if the task retries from an earlier checkpoint.
- Worker crashes: If a worker dies mid-execution, the task is requeued. If your task has non-idempotent steps, you need manual deduplication logic.
- Queue backlog: If workers can’t keep up with task ingestion, queue depth grows. Trigger.dev’s cloud auto-scales workers, but self-hosted deployments need manual scaling rules.
- Secrets rotation: If you rotate API keys, in-flight tasks may fail. Trigger.dev doesn’t have built-in secret versioning (you need external tooling).
Mitigation strategies:
- Use idempotency keys for external API calls.
- Monitor queue depth and set alerts.
- Test checkpoint recovery in staging (simulate worker crashes).
When to Use Trigger.dev vs. Alternatives
Use Trigger.dev when:
- You want durable background tasks without deploying Temporal.
- Your team is TypeScript-native and prefers code over GUI.
- You need automatic retries and checkpointing but not full event sourcing.
- You’re building agentic workflows that require programmatic control (not drag-and-drop).
Avoid Trigger.dev when:
- You need strict determinism and full workflow replay (use Temporal).
- You have non-technical users who need to build workflows (use Zapier or n8n).
- You need sub-millisecond task latency (use raw Lambda or Cloudflare Workers).
- You need complex saga patterns with compensating transactions (Temporal’s event sourcing is better).
Technical Verdict
Trigger.dev occupies a useful middle ground: more durable than raw Lambda, simpler than Temporal, more developer-friendly than Zapier. Its checkpoint-based durability is sufficient for most background jobs, and the TypeScript-native API reduces friction for teams already in that ecosystem.
The main trade-off is granularity. You lose Temporal’s full event history and strict determinism, but you gain simplicity and faster iteration. For agentic systems that need reliable multi-step workflows without heavyweight orchestration, Trigger.dev is a solid fit. For mission-critical financial transactions or complex distributed sagas, Temporal’s guarantees are worth the operational overhead.
The v2 pivot from “Zapier alternative” to “Temporal alternative” clarified the positioning. Trigger.dev is not trying to replace GUI automation tools. It’s targeting developers who want orchestration primitives in code, with enough durability to sleep at night but not so much complexity that you need a dedicated platform team.
Source Links
- Trigger.dev - Official documentation and platform
- Hacker News Discussion (745 points) - Community feedback and technical discussion
- GitHub Repository - Open-source codebase