Workflows
A workflow is an async generator function that yields steps. YieldStar compiles it into a WorkflowGenerator — the internal representation the runtime uses to execute, persist, and resume the workflow across process boundaries.
Defining a workflow
import { workflow } from "yieldstar";
const myWorkflow = workflow(async function* (step, event, logger) {
const a = yield* step.run(() => 1);
const b = yield* step.run(() => a + 1);
return b;
});The function receives three arguments:
| Argument | Type | Description |
|---|---|---|
step | StepRunner | Exposes run, delay, and poll primitives |
event | WorkflowEvent<Params, Context> | Contains workflowId, executionId, params, and context |
logger | Logger (Pino) | Structured logger scoped to the execution |
workflow and createWorkflow are aliases. Both return a WorkflowGenerator.
Type parameters
Workflows accept type parameters for input params and return type:
const processOrder = workflow<{ orderId: string }, boolean>(
async function* (step, event) {
const order = yield* step.run(() => fetchOrder(event.params.orderId));
return yield* step.run(() => processPayment(order));
}
);When registered in a router, these types flow through to the SDK so workflowId, params, and return types are enforced at the call site.
Execution model
Each time the runtime invokes a workflow, the generator replays from the beginning. Completed steps return their cached result from the heap without re-executing the step function. When the generator reaches an uncached step, it executes the function, persists the result, and continues. When it reaches a delay or a retryable error, the generator yields control back to the runtime, which schedules a wake-up and terminates the process.
On the next invocation, the generator replays all cached steps (fast, no side effects), then resumes from where it left off.
const w = workflow(async function* (step) {
// Execution 1: runs, caches result
// Execution 2: replays from cache
const a = yield* step.run(() => expensiveComputation());
// Execution 1: pauses here, schedules wake-up
// Execution 2: elapsed, continues
yield* step.delay(5000);
// Execution 2: runs, caches result
const b = yield* step.run(() => useResult(a));
return b;
});Registering workflows
Workflows are registered in a router, which maps string IDs to workflow generators:
import { createWorkflowRouter } from "yieldstar";
const router = createWorkflowRouter({
"process-order": processOrder,
"send-reminder": sendReminder,
});
export type Router = typeof router;Export the Router type to pass it to SDK factories. This gives you type-safe workflowId and params at the call site.