Code that works, without extra workers.

Durable execution means your code completes no matter what. LLM outages, API timeouts, server restarts, traffic spikes. Inngest makes every function durable without leaving your codebase.

The problem

Your workflows will fail.Then what?

Hand-rolled queues break under real load. With Inngest you retry from checkpoints, fan out work, control noisy tenants, wait for the real world, and see every step — without another worker fleet to babysit.

  • Automatic retries
  • Fan out events
  • Solve noisy neighbors
  • Wait without polling
  • Get deep observability

Compare

What is durable execution— and how does Inngest compare?

Durable execution keeps long-running workflows reliable with automatic retries and checkpoints when steps fail. Temporal gets you there if you can absorb the worker fleet and platform setup; traditional queues don't. Inngest delivers the same durability guarantees from the code you already run — no workers, no cluster, no separate orchestration fleet.

Capability
Traditional queues
Temporal
Inngest
Automatic retries
Job-level / limited
Per activity
Per-step, built in
Step-level checkpointing
Activity results cached
Every step memoized
Long sleeps / wait for events
Polling or custom infra
Signals + timers
Native sleep + waitForEvent
Multi-step durable workflows
Hand-rolled
Core strength
First-class in code
Any language / runtime
Whatever talks to the queue
Go, Java, TS, Python — Go strongest
TS, Python, Go — any HTTP runtime
Works in serverless / edge
Difficult
Persistent workers required
Native HTTP model
Native run & group scoring
DIY / external tools
step.score — runs or groups
In-code experiments
Custom traffic splitting
group.experiment() built in
Time to first durable workflow
Minutes for a basic job
Days — workers + cluster/DB (Cloud still needs a worker fleet)
Minutes — wrap existing code
Infrastructure to own
Queue, workers, DLQ
Workers always; self-host adds server + DB
Zero — fully managed

Primitives

Write durability directly into code.

Steps—or units of work—run once, cache their result, and retry independently on failure. Write normal code, wrap functions in steps, and Inngest does the rest.

step.run illustration

Flow control

Control flow through every event.

Left to a queue, work piles up, noisy tenants starve others, and APIs get hammered. Flow control is how you stay in control as volume grows.

  • ConcurrencySolve noisy neighbors
  • RateLimitControl flow
  • IdempotencyCollapse event bursts
  • PriorityExpress execution order
Flow control dashboard: concurrency caps per tenant — Acme Corp 5/5, Initech 3/5, Globex 1/5 — with a global limit of 50 split into a per-tenant cap of 5, plus a priority queue showing Sarah's new-account event ranked HIGH and two bulk-sync entries ranked NORMAL.

Observabilityby default.

To guarantee completion, Inngest tracks the state of every step. That state is the trace — every timing, input, output, and retry, captured from day one. Score runs, group outcomes, and run experiments without bolting on another tool.

Inngest dashboard showing a function run trace with per-step timings.
Waterfall TracesFunctions traced automatically, in parallel
Read the docs →
Metrics dashboardSystem health at the environment level
Read the docs →
Run searchFind the exact run for any user, org, or error pattern
Read the docs →
ReplayDeploy a fix and re-run in bulk— no dead-letter queues
Read the docs →
ScoringScore runs or groups of runs in code— quality signals on every execution
Read the docs →
ExperimentsSplit traffic across variants and compare scored outcomes in production
Read the docs →

Optionality

Any code, any runtime.

Workflows, agents, endpoints. API calls, webhooks, cron. Edge, serverless, traditional. Same primitives, same guarantees, no matter what or where you run. Wrap functions in steps to make any code durable by default.

Same primitives, any language
await step.run(“fetch-data”, async () => {
  return await db.query(...)
})
@inngest.create_function(...)
async def handler(ctx):
  data = await ctx.step.run(“fetch”, fetch)
step.Run(ctx, “fetch-data”, func(ctx) (any, error){
  return db.Query(...)
})

Why modern teams use Inngest for durable execution

Frictionless setup —for humans and agents.

Inngest pushes work to your code over HTTP. Deploy to whatever you're already running. Our integration with Stripe's Agent Provisioning Protocol also provides a zero-touch setup option: no key copying, no manual configuration, no billing review.

Terminal - Human Setup

Terminal — human setup
$ npx inngest-cli@latest dev

 Agent requests access via APP
 Connected to your functions
 Traces available at localhost:8288

No cluster. No workers. No config.

Stripe APP - Agent Provisioning

Stripe APP — Agent Provisioning
Agent requests access via APPINITIATED 0mx
Credentials provisioned automaticallyGRANTED 120ms
Functions registered, ready to runLIVE 340ms

No key copying. No billing review. No manual config.

Local-first development.

One command — npx inngest-cli dev — and you have a full execution environment running locally. No mocking, no stubs, no connecting to a remote service to test your workflow. Ship with confidence because what you ran locally is what runs in prod.

~zsh
Last login: Fri Apr 24 15:20:51 on ttys04
john@JohnnoMacBook-Pro ~ % cd workspace/demo-inngest
john@JohnnoMacBook-Pro demo-inngest % npx inngest-cli dev

What teams are building on Inngest.

Real users, real use cases.

Stop building infrastructure around your infrastructure.

Add durability to any function in minutes. Works with your existing code, wherever it runs.