Workflows
Durable TypeScript workflows built on Rivet Actors: recorded steps, retries, human approvals, and runs that resume after restarts and deploys.
Automate agent work that outlives a process. Steps record their results, wait for people or systems, and resume after crashes and deploys. Every workflow is a Rivet Actor, so each run gets the Actor’s identity, state, queue, and scheduling for free.
Quickstart
Write, run, and restart your first durable workflow.
Steps
How step results are recorded and replayed.
Failure and recovery
Retries, timeouts, and what happens after a crash.
Regular TypeScript, durable progress
A workflow is an async function. Each step records its result the first time it runs; on replay, recorded steps return instantly and the run picks up at the first step that never completed.
import {
setup,
type WorkflowStepContextOf,
workflow,
} from "@rivet-dev/workflows";
export const invoiceActor = workflow({
state: {
invoiceId: null as string | null,
subtotal: 0,
tax: 0,
total: 0,
status: "idle" as "idle" | "complete",
},
run: async (ctx) => {
const subtotal = await ctx.step("load-subtotal", async (_ctx) =>
loadSubtotal(),
);
const tax = await ctx.step("calculate-tax", async (_ctx) =>
calculateTax(subtotal),
);
await ctx.step("save-invoice", async (step) =>
saveInvoice(step, subtotal, tax),
);
},
actions: {
getState: (c) => c.state,
},
});
async function loadSubtotal(): Promise<number> {
const response = await fetch("https://api.example.com/carts/main");
if (!response.ok) {
throw new Error(`load subtotal failed: ${response.status}`);
}
const cart = (await response.json()) as {
subtotal: number;
};
return cart.subtotal;
}
async function calculateTax(subtotal: number): Promise<number> {
const response = await fetch("https://api.example.com/tax/quote", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ subtotal }),
});
if (!response.ok) {
throw new Error(`tax quote failed: ${response.status}`);
}
const quote = (await response.json()) as {
tax: number;
};
return quote.tax;
}
async function saveInvoice(
ctx: WorkflowStepContextOf<typeof invoiceActor>,
subtotal: number,
tax: number,
): Promise<void> {
const total = subtotal + tax;
const response = await fetch("https://api.example.com/invoices", {
method: "POST",
headers: {
"content-type": "application/json",
},
body: JSON.stringify({ subtotal, tax, total }),
});
if (!response.ok) {
throw new Error(`save invoice failed: ${response.status}`);
}
const invoice = (await response.json()) as {
id: string;
};
ctx.state.invoiceId = invoice.id;
ctx.state.subtotal = subtotal;
ctx.state.tax = tax;
ctx.state.total = total;
ctx.state.status = "complete";
}
export const registry = setup({ use: { invoiceActor } });
What every run inherits from its Actor
- A run per user, session, or agent. Address each workflow by key; every run keeps its own state, queue, and history.
- State beside the steps. Steps read and write the run’s durable state in-process.
- Waiting costs nothing. A run blocked on a queue wait or timer sleeps until the message or deadline arrives.
- Progress in realtime. Broadcast step progress to connected clients as it happens.
Wait, branch, and recover
Pause for approval, fan out, retry. A step can wait on a queue for a person or another system, fan into parallel branches, and join again; a failed branch retries on its own schedule while the rest continue. Every step is recorded, so a crash anywhere in the run resumes from the last completed step. Read about queue waits, timers and concurrency, and failure and recovery.
Automate agent work
Give an agent a computer with agentOS and drive it from a workflow. Each tool call, file edit, and test run is a recorded step, so the agent’s work survives restarts and is readable afterward. See agent patterns.
Evolve running work
Deploy new code mid-run. Old runs keep their version; new runs take the latest. Read about versioning.
See the history behind every run
The run inspector in the Rivet dashboard traces every step’s status, timing, attempts, inputs, outputs, and errors, and can replay eligible steps after a fix. With Rivet MCP, your AI client can inspect the Actor behind a run and diagnose failures from its workflow history.
One foundation, composable with the rest of Rivet
- Actors: every workflow is an Actor. Actors provide identity, state, queues, and scheduling.
- agentOS: adds files, processes, a shell, and networking when a workflow drives an agent using real tools.
- Dynamic Apps: adds a generated backend when the workflow should ship an application to users.
Develop locally, deploy your way
Run npm install @rivet-dev/workflows and follow the quickstart. Deploy the control plane yourself with the self-host guides, or use Rivet Cloud.