Workflows
Build stateful workflows that orchestrate complex business processes, handle long-running operations, and guarantee durable execution through automatic checkpointing and recovery.
While Dapr Workflow provides the orchestration framework, Catalyst takes you from code to production by providing a managed workflow runtime with deep observability, execution visualization, and debugging tools. Learn more about Running Workflows with Catalyst.

Workflow as Code
Dapr Workflow lets you define workflows programmatically using any supported language SDK (Python, JavaScript, .NET, Java, Go). Express complex orchestration logic with the full power and flexibility of a programming language, including conditionals, loops, error handling, and type safety.
Below is an example of an order approval workflow that demonstrates conditional logic, external events, and timeouts:
- Python
- JavaScript
- .NET
- Java
- Go
@wfr.workflow(name="request_escalation")
def request_escalation_workflow(ctx: DaprWorkflowContext, order_str: str):
order = json.loads(order_str) if isinstance(order_str, str) else order_str
amount = order.get("amount", 0)
# Auto-approve orders under $1000
if amount < 1000:
yield ctx.call_activity(auto_approve_activity, input=order)
return
# Orders $1000+ require human approval (7 days max)
approval_event = ctx.wait_for_external_event("human_approval")
timeout = ctx.create_timer(timedelta(days=7))
winner = yield when_any([approval_event, timeout])
# Handle approval event or timeout
if winner == timeout:
yield ctx.call_activity(handle_timeout_activity, input=order)
return
approval_result = approval_event.get_result()
yield ctx.call_activity(process_approval_activity, input=approval_result)
const requestEscalationWorkflow: TWorkflow = async function* (
ctx: WorkflowContext,
order: OrderRequest
): any {
// Auto-approve orders under $1000
if (order.amount < 1000) {
yield ctx.callActivity(autoApproveActivity, order);
return;
}
// Orders $1000+ require human approval (7 days max)
const approvalEvent = ctx.waitForExternalEvent("human_approval");
const timeout = ctx.createTimer(7 * 24 * 60 * 60);
const winner = yield ctx.whenAny([approvalEvent, timeout]);
// Handle approval event or timeout
if (winner == timeout) {
yield ctx.callActivity(handleTimeoutActivity, order);
return;
}
const approvalResult = approvalEvent.getResult();
yield ctx.callActivity(processApprovalActivity, approvalResult);
};
// Workflow Definition
public class RequestEscalationWorkflow : Workflow<OrderRequest, object>
{
public override async Task<object> RunAsync(WorkflowContext context, OrderRequest order)
{
// Auto-approve orders under $1000
if (order.Amount < 1000)
{
await context.CallActivityAsync(nameof(AutoApproveActivity), order);
return null;
}
// Orders $1000+ require human approval (7 days max)
try
{
var approval = await context.WaitForExternalEventAsync<ApprovalResult>(
eventName: "human_approval",
timeout: TimeSpan.FromDays(7));
// Handle approval event
await context.CallActivityAsync(nameof(ProcessApprovalActivity), approval);
return null;
}
catch (TaskCanceledException)
{
// Handle timeout - no approval received within 7 days
await context.CallActivityAsync(nameof(HandleTimeoutActivity), order);
return null;
}
}
}
// Workflow Definition
@Component
public static class RequestEscalationWorkflow implements Workflow {
@Override
public WorkflowStub create() {
return ctx -> {
OrderRequest order = ctx.getInput(OrderRequest.class);
// Auto-approve orders under $1000
if (order.amount < 1000) {
ctx.callActivity("AutoApproveActivity", order).await();
ctx.complete("approved");
return;
}
// Orders $1000+ require human approval (7 days max)
try {
ApprovalResult approval = ctx.waitForExternalEvent("human_approval", Duration.ofDays(7), ApprovalResult.class).await();
ctx.callActivity("ProcessApprovalActivity", approval).await();
} catch (TaskCanceledException e) {
// Handle timeout
ctx.callActivity("HandleTimeoutActivity", order).await();
}
ctx.complete("order completed");
};
}
}
// Workflow Definition
func RequestEscalationWorkflow(ctx *workflow.WorkflowContext) (any, error) {
var order OrderRequest
if err := ctx.GetInput(&order); err != nil {
return nil, err
}
// Auto-approve orders under $1000
if order.Amount < 1000 {
return nil, ctx.CallActivity(AutoApproveActivity, workflow.WithActivityInput(order)).Await(nil)
}
// Orders $1000+ require human approval (7 days max)
var approval ApprovalResult
err := ctx.WaitForExternalEvent("human_approval", time.Hour*24*7).Await(&approval)
// Handle approval event or timeout
if err == nil {
return nil, ctx.CallActivity(ProcessApprovalActivity, workflow.WithActivityInput(approval)).Await(nil)
}
return nil, ctx.CallActivity(HandleTimeoutActivity, workflow.WithActivityInput(order)).Await(nil)
}
Key capabilities:
- Durability - Every workflow step is persisted in a backing store (SQL, NoSQL, or cloud service), allowing workflows to survive process restarts and continue from their last recorded state
- Built-in resiliency - Durable retry policies track retry state, wait with durable timers, and continue after restarts with automatic retries, timeouts, and circuit breakers
- Child workflows - Compose complex processes by breaking them down into reusable sub-processes
- Multi-application workflows - Orchestrate business processes that span different application instances, enabling workflow and activity reuse across services
- Timers and reminders - Schedule delays or future events with durable timer support
- External events - Wait for human approvals, external system responses, or custom triggers
Workflow Patterns
Dapr Workflow supports common stateful coordination patterns in microservice architectures.
Task Chaining

Multiple steps in a workflow run in succession, with the output of one step passed as input to the next step. Ideal for sequential data processing operations like filtering, transforming, and reducing.
Read more →Fan-out/Fan-in

Execute multiple tasks simultaneously across potentially multiple workers, wait for them to finish, and perform aggregation on the results. Perfect for parallel processing with dynamic task counts.
Read more →Async HTTP APIs

Implement asynchronous request-reply patterns where clients receive immediate acknowledgment and can poll for completion status. Built-in support for long-running operations without custom state management.
Read more →Monitor

Recurring process that checks system status, takes action based on that status, sleeps for a period, and repeats. Supports dynamic sleep intervals and graceful termination.
Read more →External System Interaction

Pause and wait for external systems or human input to perform actions. Supports timeouts, event-driven resumption, and compensation logic for approval workflows and payment processing.
Read more →Compensation

Roll back or undo operations that have already been executed when a workflow fails partway through. Essential for maintaining consistency in distributed transactions across microservices.
Read more →Running and Operating Workflows with Catalyst
Catalyst provides deep workflow observability through a unified dashboard that tracks all executions, workflow states, and success rates. View summaries by workflow type, drill down into individual runs, and visualize execution paths to understand how each activity progressed or failed.

Key capabilities:
- Workflow dashboard - Monitor workflow execution states (Running, Completed, Failed) and aggregate success rates across workflows for quick health insights
- Execution visualization - View real-time diagrams of workflow paths, including branching, parallel activities, and dependencies
- Execution history - View full workflow timelines, duration, and outcomes for debugging and auditing
- Input and output inspection - Examine data at each stage for debugging and monitoring
- API logs - Inspect real-time Dapr API calls including Workflow, State, Pub/Sub, and Invocation APIs for end-to-end visibility