Workflows
Cloudflare Workflows provide durable, multi-step execution for tasks that need to survive failures, retry automatically, and wait for external events. When integrated with Agents, Workflows handle long-running background processing while Agents manage real-time communication.
Agents and Workflows have complementary strengths:
| Capability | Agents | Workflows |
|---|---|---|
| Execution model | Can run indefinitely | Run to completion |
| Real-time communication | WebSockets, HTTP streaming | Not supported |
| State persistence | Built-in SQL database | Step-level persistence |
| Failure handling | Application-defined | Automatic retries and recovery |
| External events | Direct handling | Pause and wait for events |
| User interaction | Direct (chat, UI) | Through Agent callbacks |
Agents can loop, branch, and interact directly with users. Workflows execute steps sequentially with guaranteed delivery and can pause for days waiting for approvals or external data.
Use Agents alone for:
- Chat and messaging applications
- Quick API calls and responses
- Real-time collaborative features
- Tasks under 30 seconds
Use Agents with Workflows for:
- Data processing pipelines
- Report generation
- Human-in-the-loop approval flows
- Tasks requiring guaranteed delivery
- Multi-step operations with retry requirements
Use Workflows alone for:
- Background jobs with or without user approval
- Scheduled data synchronization
- Event-driven processing pipelines
The AgentWorkflow class (imported from agents/workflows) provides bidirectional communication between Workflows and their originating Agent.
Workflows can communicate with Agents through several mechanisms:
- RPC calls: Directly call Agent methods with full type safety via
this.agent - Progress reporting: Send progress updates via
this.reportProgress()that trigger Agent callbacks - State updates: Modify Agent state via
step.updateAgentState()orstep.mergeAgentState(), which broadcasts to connected clients - Client broadcasts: Send messages to all WebSocket clients via
this.broadcastToClients()
// Inside a workflow's run() methodawait this.agent.updateTaskStatus(taskId, "processing"); // RPC callawait this.reportProgress({ step: "process", percent: 0.5 }); // Progress (non-durable)this.broadcastToClients({ type: "update", taskId }); // Broadcast (non-durable)await step.mergeAgentState({ taskProgress: 0.5 }); // State update (durable)// Inside a workflow's run() methodawait this.agent.updateTaskStatus(taskId, "processing"); // RPC callawait this.reportProgress({ step: "process", percent: 0.5 }); // Progress (non-durable)this.broadcastToClients({ type: "update", taskId }); // Broadcast (non-durable)await step.mergeAgentState({ taskProgress: 0.5 }); // State update (durable)Agents can interact with running Workflows by:
- Starting workflows: Launch new workflow instances with
runWorkflow() - Sending events: Dispatch events with
sendWorkflowEvent() - Approval/rejection: Respond to approval requests with
approveWorkflow()/rejectWorkflow() - Workflow control: Pause, resume, terminate, or restart workflows
- Status queries: Check workflow progress with
getWorkflow()/getWorkflows()
Understanding durability is key to using workflows effectively:
These operations are lightweight and suitable for frequent updates, but may execute multiple times if the workflow retries:
this.reportProgress()— Progress reportingthis.broadcastToClients()— WebSocket broadcasts- Direct RPC calls to
this.agent
These operations use the step parameter and are guaranteed to execute exactly once:
step.do()— Execute durable stepsstep.reportComplete()/step.reportError()— Completion reportingstep.sendEvent()— Custom eventsstep.updateAgentState()/step.mergeAgentState()— State synchronization
Workflows provide durability through step-based execution:
- Step completion is permanent — Once a step completes, it will not re-execute even if the workflow restarts
- Automatic retries — Failed steps retry with configurable backoff
- Event persistence — Workflows can wait for events for up to one year
- State recovery — Workflow state survives infrastructure failures
This durability model means workflows are well-suited for tasks where partial completion must be preserved, such as multi-stage data processing or transactions spanning multiple systems.
When an Agent starts a workflow using runWorkflow(), the workflow is automatically tracked in the Agent's internal database. This enables:
- Querying workflow status by ID, name, or metadata with cursor-based pagination
- Monitoring progress through lifecycle callbacks (
onWorkflowProgress,onWorkflowComplete,onWorkflowError) - Workflow control: pause, resume, terminate, restart
- Cleaning up completed workflow records with
deleteWorkflow()/deleteWorkflows() - Correlating workflows with users or sessions through metadata
An Agent receives a request, starts a Workflow for heavy processing, and broadcasts progress updates to connected clients as the Workflow executes each step.
// Workflow reports progress after each itemfor (let i = 0; i < items.length; i++) { await step.do(`process-${i}`, async () => processItem(items[i])); await this.reportProgress({ step: `process-${i}`, percent: (i + 1) / items.length, message: `Processed ${i + 1}/${items.length}`, });}// Workflow reports progress after each itemfor (let i = 0; i < items.length; i++) { await step.do(`process-${i}`, async () => processItem(items[i])); await this.reportProgress({ step: `process-${i}`, percent: (i + 1) / items.length, message: `Processed ${i + 1}/${items.length}`, });}A Workflow prepares a request, pauses to wait for approval using waitForApproval(), and the Agent provides UI for users to approve or reject via approveWorkflow() / rejectWorkflow(). The Workflow resumes or throws WorkflowRejectedError based on the decision.
A Workflow wraps external API calls in durable steps with retry logic. If the API fails or the workflow restarts, completed calls are not repeated and failed calls retry automatically.
const result = await step.do( "call-api", { retries: { limit: 5, delay: "10 seconds", backoff: "exponential" }, timeout: "5 minutes", }, async () => { const response = await fetch("https://api.example.com/process"); if (!response.ok) throw new Error(`API error: ${response.status}`); return response.json(); },);const result = await step.do( "call-api", { retries: { limit: 5, delay: "10 seconds", backoff: "exponential" }, timeout: "5 minutes", }, async () => { const response = await fetch("https://api.example.com/process"); if (!response.ok) throw new Error(`API error: ${response.status}`); return response.json(); },);A Workflow updates Agent state at key milestones using step.updateAgentState() or step.mergeAgentState(). These state changes broadcast to all connected clients, keeping UIs synchronized without polling.
- Run Workflows API reference for implementation details
- Cloudflare Workflows documentation for workflow fundamentals
- Human-in-the-loop patterns for approval flows
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2026 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-