Conditional Steps & Early Exit
Conditional steps with stepIf
Section titled “Conditional steps with stepIf”stepIf runs the handler only when the condition returns true. Skipped steps don’t affect state and don’t consume retry attempts.
flow .step('checkCache', (ctx) => { return { cached: cache.has(ctx.input.key) }; }) .stepIf('fromCache', (ctx) => ctx.state.cached, (ctx) => { return { value: cache.get(ctx.input.key) }; }) .stepIf('fromDb', (ctx) => !ctx.state.cached, async (ctx) => { return { value: await db.get(ctx.input.key) }; })Skipped steps trigger the onStepSkipped observer hook if an observer is attached.
Early exit with breakIf
Section titled “Early exit with breakIf”breakIf short-circuits the flow, skipping all remaining steps and the .map() transformer. This is useful for early returns when further processing is unnecessary.
flow .step('findUser', async (ctx) => { const existing = await db.findByEmail(ctx.input.email); return { existing }; }) .breakIf( (ctx) => ctx.state.existing != null, (ctx) => ({ user: ctx.state.existing, created: false }) ) .step('createUser', async (ctx) => { const user = await db.createUser(ctx.input); return { user }; }) .map((input, state) => ({ user: state.user, created: true })) .build();How breakIf works
Section titled “How breakIf works”- The first argument is the condition — if it returns
true, the flow exits early - The second argument (optional) defines the return value — this is what
.execute()resolves to when the break triggers - If no return value is provided, the current accumulated state is returned
- The
.map()transformer is skipped when a break occurs
Type safety
Section titled “Type safety”The return type of .execute() is a union of the normal output and all possible break outputs. TypeScript tracks this automatically.
const result = await flow.execute(input, deps);// result: { user: User; created: true } | { user: User; created: false }