open-source orchestration engine for background tasks, AI agents, and durable workflows — durable execution built on Postgres

Short version: if your agent runs for minutes or hours, the hard part isn't the prompt — it's making the run survive a crash, a rate-limit, or a Friday deploy without redoing everything it already paid for. Hatchet is an MIT-licensed orchestration engine (YC W24, 7.7k stars) that gives you that durability, and its one distinguishing move is where it keeps the state: PostgreSQL — the database you already run — instead of a dedicated cluster.

What it is, in one screen#

Hatchet describes itself as "an orchestration engine for background tasks, AI agents, and durable workflows." In practice it's a durable task queue: you break work into steps, Hatchet schedules them across your workers, persists each completed step, and — when something fails — retries on a policy you set instead of collapsing the whole run. That's the same durable execution pattern behind Temporal, Inngest, and Restate, which we've walked through before as a category.

The thing that makes it worth a solo founder's attention is the durability layer. Most engines in this space bring their own datastore and broker to operate. Hatchet uses Postgres for both the task runtime and the observability system, so self-hosting is a Docker image against a database you already know how to back up — not a new stateful service on your on-call rotation.

Temporal gives you durable execution and a cluster to run. Hatchet gives you durable execution and a table in a database you already run. For a two-person team, that difference is whether the pattern ships at all.

Why an agent needs this#

An agent that runs for hours is a long chain of expensive, side-effecting steps: LLM calls you paid for, tools that mutated real state, files written. If the process dies at step 14 of 20 and your only recovery is "run it again," you re-pay for steps 1–13 and risk firing their side effects twice. Durable execution turns each completed step into a checkpoint: a resumed run picks up at 14, and a step that failed on a transient error retries on its own.

Here's the shape in the Python SDK — a task with a retry policy and a durable step:

from hatchet_sdk import Hatchet

hatchet = Hatchet()

@hatchet.task(retries=3, backoff_factor=2)     # retry transient failures, backing off
async def research_agent(input, ctx):
    # ctx.run persists this step's result; a resumed run skips it
    plan = await ctx.run("plan", lambda: llm_plan(input.topic))
    notes = []
    for step in plan.steps:                    # a 40-minute loop that survives a crash
        notes.append(await ctx.run(f"do:{step.id}", lambda: execute(step)))
    return {"report": await ctx.run("write", lambda: synthesize(notes))}

You get flexible retries with exponential backoff, event-based triggers, rate limits and concurrency controls, plus a real-time web UI, OpenTelemetry traces, and Prometheus metrics without wiring your own. SDKs cover Python, TypeScript, Go, and Ruby.

Getting started#

The honest caveat#

Durable execution is a design commitment, not a decorator you sprinkle on at the end. To get the guarantees you have to decompose your agent into idempotent, replayable steps — real work, and the reason not every agent should adopt it on day one. If your runs are short, stateless, and cheap to redo, you don't need Hatchet yet. Reach for it the first time a run that dies at minute 40 costs you the whole 40 minutes — that's the day durability stops being overhead and starts being the product.