Cloudflare Workflows Gets Saga Rollbacks — No More Manual Compensation Logic
Cloudflare ships saga rollbacks for Workflows, letting you define compensation logic inline with each step.do() call. No more manual catch blocks and reverse-ordered undo code.

Cloudflare Workflows now supports the saga pattern natively. Instead of wrapping every step in try-catch and manually tracking what to undo, you can pass a rollback function as an option to step.do(). If a later step fails, Workflows runs the rollback handlers in reverse step-start order — exactly what you need for distributed transactions.
Why Saga Rollbacks Matter
Long-running workflows often touch multiple external systems. A fund transfer might debit account A, credit account B, then send a notification. If the credit fails, you can't just undo the debit — you need a compensating action (a reverse credit). That's the saga pattern. Before this release, developers had to implement that compensation manually, tracking which steps succeeded and writing reverse logic in a catch block. It was error-prone and verbose.
Now you write:
await step.do("debit-bank-a", () => bankA.debit(from, amount), {
rollback: async ({ output }) => bankA.credit(from, amount, output.id),
});
await step.do("credit-bank-b", () => bankB.credit(to, amount), {
rollback: async ({ output }) => bankB.debit(to, amount, output.id),
});
await step.do("notify", () => notifyBoth(from, to, amount));The rollback handler lives right next to the forward operation. No separate catch block, no manual ordering. Workflows handles the rest.
Key Design Decisions
The team considered a fluent API (step.do(...).rollback(...)) but rejected it. The problem: step.do() returns a promise, and Workers supports promise pipelining (a Cap'n Proto feature that lets you call methods on a future value before it resolves). A fluent API would make it ambiguous whether .rollback() is part of the step definition or a method on the output. It would also delay step execution — Workflows would need to wait and see if .rollback() gets attached before starting the step. The current options-based API keeps step execution immediate and predictable.
Rollback only triggers when the workflow is about to fail terminally. If you catch an error and continue, rollback doesn't run. The failed step itself is eligible for rollback if it registered a handler — important because a step might have partially interacted with an external system before failing. The rollback handler receives output (which may be undefined) so you can decide what to undo.
For parallel steps, rollback order uses reverse step-start order, not completion order. This avoids ambiguity when steps complete in a different order than they started.
The Bottom Line
This is a solid, pragmatic API for a common distributed systems pattern. If you're building multi-step workflows on Cloudflare Workers, sagas just got a lot less painful. The idempotency key pattern shown in the docs is a must-follow — make both forward and rollback operations idempotent to avoid double-apply on retries.
Discussion
0 Comments
Be the first to start the discussion.