Durable background work, in plain async .

Waymark lets you write workflows as regular code.

Compile backend logic into deterministic programs and run them on a durable, interruptible VM backed by Postgres.

This lets your logic survive restarts, crashes, and week-long sleeps. All without any broker, inefficient replays, or errors.

Bye bye scaling RabbitMQ.

charge_workflow.py
import asyncio
from waymark import Workflow, action, workflow
@action
async def charge(order_id: int) -> bool:
return await payments.charge(order_id)
@workflow
class Checkout(Workflow):
async def run(self, order_id: int) -> str:
for _ in range(3):
if await charge(order_id):
return "paid"
# durable: survives restarts
await asyncio.sleep(3600)
return "failed"

01Your backend logic is simpler (and safer) when it's durable.

Backend logic is complex enough already. You're integrating your own services, 3rd party API calls, objects from your database, etc. It's easy to do that in a simple script, but the second you hit real production infrastructure it becomes a lot more difficult.

How do you deal with load balancing across multiple boxes? How do you keep going even when containers crash and restart, without redoing a non-idempotent action?

Historically you'd need to hand roll connectors, or constrain your logic to a 3rd party language. Durable execution flips that script. You write the whole flow as one ordinary function, and the engine remembers its state. Crashes, restarts, and hour-long waits simply resume where they left off.

Waymark is durable execution that's easy to live with. It compiles your workflow instead of replaying it, so determinism is verified up front (no runtime surprises) and execution is faster. It lives on the Postgres you already have, so you'll already know how to tune performance.

02What you get out of the box.

  1. 01 · No surprise errors

    If it compiles, it runs as advertised.

    Waymark verifies your workflow when you register it. Nondeterministic calls like datetime.now() or uuid4() are rejected with a recommendation to move them into an @action. If it runs it's good to go.

    Compilation lets us have ulta-fast restores after sleeps since we also don't need to hydrate variable state in an interpreted runtime.

  2. 02 · No double charges

    Safe logic even in a crash.

    Without waymark, jobs that die halfway risk getting retried from the top. Unless every action has no side-effects, that's a problem. Waymark saves each action's result the moment it finishes. After a restart it resumes at the step that was interrupted.

  3. 03 · Plain async Python

    Real control flow, no DSL.

    Workflows support most native logic in your language: loops, conditionals, try/except, gathers to name a few. Actions, of course, can do anything you want.

    You worry about writing ordinary async Python, we'll worry about running it as miniature VMs distributed across every core.

  4. 04 · Just Postgres

    No broker, no second system.

    Waymark runs on the Postgres you already have. It scales to surprisingly heavy load out of the box and benefits from the same Postgres tuning you already do. No Redis, no hosted queue, no extra service to deploy and babysit.

  5. 05 · Management dashboard

    See every run, live.

    A beautiful web dashboard ships in the box. Watch workflows progress in real time and drill into any run to see success and failure. In addition to your logs it's a very powerful tool to see what's happening behind the scenes.

03Add it and go.

Waymark ships as a single Python package and runs on the Postgres you already have. Point the workers at your database, queue a workflow, and it runs durably across your cluster.
quickstart
$ uv add waymark
$ export WAYMARK_DATABASE_URL=...
$ uv run waymark-executor
→ workers ready, queue a workflow

04One engine for every language.

Waymark workflows run a small IR on a durable VM written in Rust. The Python SDK is a thin layer on top: a compiler that lowers your async functions into that IR and a worker that executes your actions.
This lets us treat a new language as another frontend, not a new engine, so adding one is a much smaller job than you'd think. Every speedup we land in the runtime makes every language faster with no additional work. It's the closest thing we have to a free lunch.

What should we build next?

We're currently taking community feedback to see what we build next. Vote for your favorite and maybe you'll even get a prize.

Languages
Pythonshipped

You'll also get occasional Waymark updates. Unsubscribe anytime.

Following the work on GitHub: TypeScript · Go · Rust

05Questions.

How is this different from Temporal or Vercel Workflows?
Unlike Waymark, both are replay-based. After a restart they rebuild a workflow's state by running its code again against an event history, so every step before the crash needs to re-populate memory with active vars. Waymark persists just the state it needs at each step and resumes from there. Because nothing replays, determinism is verified when you register the workflow instead of surfacing in production.
Do I need Redis or a message broker?
No. Waymark runs on the Postgres you already have, driven by a Rust runtime that handles the queueing and scheduling for you.
But *technically* my actions could crash half way through and need to be idempotent anyway right??
Yes - technically true! But because we register when actions start/finish, we leave that choice up to you. If something is risky to re-run naively, set its max_runs to 1 and write an Exception wrapper to manually rollback from the corrupt state.

Make your background jobs unbreakable.

Plain async Python, durable on the Postgres you already run.

Stay in the loop

Get the updates.

New features, release notes, and durable-execution deep dives for Waymark. Occasional, no spam.

No spam. Unsubscribe anytime.