Conditional Branching
Skip steps dynamically based on runtime conditions using JavaScript expressions.
Overview
Conditional branching allows you to skip steps based on the output of previous steps or the initial workflow input. This enables dynamic workflow routing without complex orchestration code.
Basic Usage
Add a condition to any step to control whether it executes:
1import { relay } from "@relayplane/sdk";23const result = await relay4 .workflow("ticket-router")5 .step("classify")6 .with("openai:gpt-4o")7 .prompt("Classify this ticket as 'urgent' or 'normal': {{input.text}}")89 // Only runs if classification is urgent10 .step("escalate", {11 condition: "steps.classify.output.category === 'urgent'"12 })13 .with("anthropic:claude-sonnet-4-20250514")14 .depends("classify")15 .prompt("Generate escalation message for: {{input.text}}")1617 // Only runs if classification is normal18 .step("auto-reply", {19 condition: "steps.classify.output.category === 'normal'"20 })21 .with("openai:gpt-4o-mini")22 .depends("classify")23 .prompt("Generate auto-reply for: {{input.text}}")2425 .run({ text: "My server is on fire!" });Condition Syntax
Conditions are JavaScript expressions with access to:
- •
input- The workflow's initial input - •
steps- Object containing outputs from completed steps
1// Access workflow input2condition: "input.priority === 'high'"34// Access step output5condition: "steps.classify.output.confidence > 0.8"67// Complex conditions8condition: "steps.extract.output && steps.extract.output.total > 1000"910// String matching11condition: "steps.classify.output.category === 'urgent'"1213// Array checks14condition: "steps.extract.output.items.length > 0"1516// Boolean logic17condition: "steps.check.output.isValid && input.autoApprove"Conditions must return a truthy or falsy value. If a condition throws an error, the step is skipped and the error is logged.
Common Patterns
If/Else Pattern
1// Mutually exclusive branches2.step("handle-yes", {3 condition: "steps.decide.output.answer === 'yes'"4})5.depends("decide")67.step("handle-no", {8 condition: "steps.decide.output.answer === 'no'"9})10.depends("decide")Threshold Pattern
1// Only process if confidence is high enough2.step("process", {3 condition: "steps.analyze.output.confidence >= 0.9"4})5.depends("analyze")67// Fallback for low confidence8.step("manual-review", {9 condition: "steps.analyze.output.confidence < 0.9"10})11.depends("analyze")Feature Flag Pattern
1// Optional step based on input flag2.step("enhanced-analysis", {3 condition: "input.enableEnhancedAnalysis === true"4})5.depends("basic-analysis")Handling Skipped Steps
When a step is skipped, it appears in the result with a skipped flag:
1const result = await workflow.run(input);23for (const step of result.steps) {4 if (step.skipped) {5 console.log(`Step ${step.stepName} was skipped: ${step.skipReason}`);6 } else {7 console.log(`Step ${step.stepName} completed with output:`, step.output);8 }9}Complete Example
1import { relay } from "@relayplane/sdk";23const result = await relay4 .workflow("document-processor")56 // Step 1: Classify the document7 .step("classify")8 .with("openai:gpt-4o")9 .prompt("Classify this document type: invoice, contract, or other")1011 // Step 2a: Process invoices12 .step("extract-invoice", {13 condition: "steps.classify.output.type === 'invoice'"14 })15 .with("openai:gpt-4o")16 .depends("classify")17 .prompt("Extract invoice fields: vendor, amount, date, line items")1819 // Step 2b: Process contracts20 .step("extract-contract", {21 condition: "steps.classify.output.type === 'contract'"22 })23 .with("anthropic:claude-sonnet-4-20250514")24 .depends("classify")25 .prompt("Extract contract fields: parties, terms, dates")2627 // Step 2c: Handle unknown documents28 .step("flag-unknown", {29 condition: "steps.classify.output.type === 'other'"30 })31 .with("openai:gpt-4o-mini")32 .depends("classify")33 .prompt("Flag for manual review with summary")3435 .run({ document: documentText });3637// Only one of the three processing steps will have executed38console.log("Executed steps:",39 result.steps.filter(s => !s.skipped).map(s => s.stepName)40);See also: Parallel Execution | Core Concepts