Skip to content
Ironflow is pre-1.0: APIs can change between releases. Pin a version. What is ready →

Workflows

Ironflow executes workflows durably, records events, derives projections, and lets you time-travel through execution history. Workflows survive crashes, retries, and restarts automatically; completed steps are memoized, and with recording enabled every step becomes a recorded fact.

ConceptDescription
FunctionA workflow definition that responds to events. Contains one or more steps.
StepA recorded fact within a function. Steps are memoized—if a workflow restarts, completed steps aren’t re-executed.
EventA recorded fact that triggers a workflow (e.g., order.placed, user.signup). Kept until you prune or delete it.
RunA single execution of a function, triggered by an event.

How it works:

  1. You define functions with steps using the SDK
  2. Register functions with the Ironflow server (push or pull mode)
  3. Trigger events from your application
  4. Ironflow executes functions, memoizing each step result and — with recording: true — recording it as a fact, enabling replay, debugging, and history navigation

Real-time events: For subscribing to workflow events in real-time, see the Events & Pub/Sub guide.

Durable Workflow Execution — showing memoized steps, failure recovery, and parallel branches


Automatic sleep, event, child-invocation, retry, and recovery waits report waiting. An execution segment awaiting capacity reports waiting_for_capacity. An explicit operator hold reports paused.

A run that used up its retry attempts on retryable failures also reports paused, with pause reason retries_exhausted and the last error attached. That is the default; a function (or spec.engine.retry.onExhausted) can choose fail instead. A paused run is not over: it keeps its memoized steps, holds no capacity, and waits for ironflow run resume, which grants it a fresh retry budget. See Error handling.

You can pause or cancel a waiting run. Resume removes an operator hold and preserves the original condition and deadline: an unresolved wait returns to waiting, and a completed condition continues automatically. An event that arrives before the deadline during the hold stays pending and applies shortly after Resume.

The @ironflow/* npm packages are public and install without authentication.

Terminal window
npm install @ironflow/node
# or
pnpm add @ironflow/node

Terminal window
# Build first. `embed` matters: a plain `make build` produces a binary whose
# `serve` exits "embedded dashboard missing (static/index.html not found)".
make embed build
# Start Ironflow server
./build/ironflow serve
# Dashboard: http://localhost:9123
# API: http://localhost:9123/api/v1

Register your function endpoint in the dashboard or via API, then trigger events to test.


Here’s a minimal workflow to get started:

import { ironflow } from "@ironflow/node";
export const helloWorld = ironflow.createFunction(
{
id: "hello-world",
triggers: [{ event: "hello.triggered" }],
},
async ({ event, step }) => {
const message = await step.run("create-message", async () => {
return `Hello, ${event.data.name}!`;
});
return { message };
},
);

Workflows run when a matching event is sent. You can trigger events from your application code, the CLI, or the REST API.

import { createClient } from "@ironflow/node";
const client = createClient({ serverUrl: "http://localhost:9123" });
// Fire-and-forget
await client.emit("hello.triggered", { name: "Alice" });
// Wait for every run the event triggers
const results = await client.emitSync("hello.triggered", { name: "Alice" });
// Or target one function by ID and wait for its single result
const result = await client.invoke("hello-world", { data: { name: "Alice" } });

You can also invoke a function directly by ID, bypassing event matching. Every SDK has a blocking form — InvokeSync in Go, invoke() in Node and the browser, rpc.runs.invoke_function_sync on the Python IronflowRPC client — over the InvokeFunctionSync RPC; it returns exactly one result and raises on a failed run. For the non-blocking form see the REST API reference for the InvokeFunction RPC. The split between the two is recorded in ADR 0067.

The underlying gRPC IronflowService exposes the event-ingestion RPCs SDKs and tooling use directly: Trigger and Emit (fire-and-forget event publish), TriggerSync (publish and wait for every matched run to complete), InvokeFunctionSync (run one function by ID and wait for its single result), TriggerBatch (batch publish; a failed item reports its error and the other items still emit), and PatchStep (scoped injection — overwrite a completed step’s output and resume). See the generated api/ironflow/v1 package on the public Go mirror for the full service definition.

For more details on event types, namespaces, and pattern matching, see the Events guide. SDK-specific options (idempotency keys, metadata, timeouts) are covered in the Node.js SDK, Browser SDK, and Go SDK references.


  • Defining Functions — Learn about function configuration and triggers
  • Step Primitives — Understand run, sleep, sleepUntil, waitForEvent, parallel, map, compensate, invoke, invokeAsync, and publish
  • Execution Modes — Push mode vs. Pull mode
  • Error Handling — NonRetryableError and signature verification
  • Sagas & Compensation — Automatically undo completed steps on failure
  • Debugging — Hot patching, scoped injection, time-travel debugging, TUI debugger, VS Code DAP
  • API Reference — REST API, Events API, WebSocket