Skip to main content

Workflows

Stem workflows are the durable orchestration layer on top of the normal Stem task runtime. They let you model multi-step business processes, suspend on time or external events, resume on another worker, and inspect the full run state from the store, CLI, or dashboard.

Use this section as the main workflow manual. The older Core Concepts > Workflows page now just orients you and links back here.

Pick a workflow style

  • Flow: a declared sequence of durable steps. Use this when you want the workflow structure to be the source of truth.
  • WorkflowScript: a durable async function. Use this when normal Dart control flow should define the execution plan.
  • Annotated workflows with stem_builder: use annotations and generated workflow refs when you want plain method signatures and less string-based wiring.

Read this section in order

Runtime bootstrap

bin/workflows.dart
  final client = await StemClient.fromUrl(
'redis://127.0.0.1:56379',
adapters: const [StemRedisAdapter(), StemPostgresAdapter()],
overrides: const StemStoreOverrides(
backend: 'redis://127.0.0.1:56379/1',
workflow: 'postgresql://<user>:<password>@127.0.0.1:65432/stem',
),
);
final workflowApp = await client.createWorkflowApp(
flows: [ApprovalsFlow.flow],
scripts: [retryScript],
eventBusFactory: WorkflowEventBusFactory.inMemory(),
workerConfig: const StemWorkerConfig(queue: 'workflow'),
);
bin/workflows.dart
  await workflowApp.start();

StemWorkflowApp is the recommended entrypoint because it wires:

  • the underlying StemApp
  • the workflow runtime
  • the workflow store
  • the workflow event bus
  • the managed worker that executes the internal stem.workflow.run task

If you already own a StemClient, you can attach workflow support through that shared client instead of constructing a second app boundary:

final client = await StemClient.fromUrl('memory://');
final workflowApp = await client.createWorkflowApp(
flows: [ApprovalsFlow.flow],
scripts: [retryScript],
);

If your service already owns a StemApp, layer workflows on top of it with stemApp.createWorkflowApp(...). That path reuses the existing worker, so the app must already subscribe to the workflow queue plus any task queues the workflows need.