Skip to content

Authoring Workflows ​

Use this sequence for every durable workflow family.

1. Name Stable Payloads ​

Create reusable Schema values for input, success, and expected failure. Validation belongs here when it is intrinsic to the payload.

2. Declare Definitions ​

Use Workflow, Operation, Work, and Event. Treat code + version and name + version as published identities.

3. Implement the Workflow ​

Call definition.implement(...). Keep the handler deterministic:

  • branch only on input or recorded results;
  • use a stable id for every durable operation;
  • call workflow.perform(...) for automated work;
  • call request, waitForEvent, query, workflow, spawn, join, sleep, and structured-concurrency operations directly on the same workflow scope;
  • never call databases, HTTP, wall clocks, randomness, or mutable globals.

4. Implement Operations ​

Call Operation.implement(...) for each real handler. Forward operation.context.idempotencyKey to the external system or effect receipt.

5. Compose a Module ​

dart
final module = WorkflowModule(
  name: 'orders',
  workflows: [orderHandler],
  operations: [reserveHandler, publishHandler],
  work: [approveOrder],
  events: [orderChanged],
);

Install modules when constructing the runtime or server. Do not mutate registries after startup.

6. Version Deliberately ​

Changing orchestration behavior requires a new workflow version. Changing a data incompatibly requires a new schema version and usually a new workflow or operation version.

Review Checklist ​

  • Every await has a stable semantic ID.
  • Every external effect is in an operation handler.
  • Every handler can safely replay or retry.
  • Expected failures use the typed E channel.
  • Work audiences come from trusted product policy.
  • The module installs every referenced handler and interaction contract.
  • Tests cover replay across every blocking boundary.