Cloudflare Workflows — durable multi-step execution.
Workflows provide durable execution for multi-step processes. Unlike Queues (fire-and-forget) or Durable Objects (stateful compute), Workflows let you define a sequence of steps where each step can retry independently and the overall state persists even if the Worker restarts.
Status: Open beta on Workers Paid plan.
[[workflows]]
name = "brief-analysis"
binding = "BRIEF_WORKFLOW"
class_name = "BriefAnalysisWorkflow"
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';
interface BriefParams {
projectId: string;
userId: string;
briefText: string;
}
export class BriefAnalysisWorkflow extends WorkflowEntrypoint<Env, BriefParams> {
async run(event: WorkflowEvent<BriefParams>, step: WorkflowStep): Promise<void> {
const { projectId, userId, briefText } = event.payload;
// Step 1: Classify the brief (retries automatically on failure)
const classification = await step.do('classify-intent', async () => {
return classifyWithWorkersAI(briefText, this.env);
});
// Step 2: Retrieve relevant skills via Vectorize (parallel)
const [skills, userProfile] = await Promise.all([
step.do('retrieve-skills', async () => {
return searchSkills(briefText, classification.domain, this.env);
}),
step.do('load-user-profile', async () => {
return loadUser(userId, this.env);
}),
]);
// Step 3: Generate AI analysis (expensive — retried if it fails)
const analysis = await step.do('generate-analysis', async () => {
return generateAnalysis({ briefText, classification, skills, userProfile }, this.env);
});
// Step 4: Persist results + notify user
await step.do('save-results', async () => {
await this.env.DB.prepare('UPDATE projects SET analysis = ?, status = ? WHERE id = ?')
.bind(JSON.stringify(analysis), 'complete', projectId)
.run();
});
// step.sleep() for scheduled follow-ups
await step.sleep('wait-before-notify', '5 minutes');
await step.do('send-notification', async () => {
await sendEmail(userProfile.email, 'Your analysis is ready', analysis, this.env);
});
}
}
// Start a workflow instance
const instance = await env.BRIEF_WORKFLOW.create({
id: `brief-${projectId}`, // deterministic ID — idempotent
params: { projectId, userId, briefText },
});
// Check status
const status = await instance.status();
console.log(status.status); // 'running' | 'complete' | 'errored' | 'paused'
compatibility_date and check release notes.step.do() caches results: Once a step completes, its result is persisted. Subsequent runs of the Workflow skip completed steps.step.sleep() instead of setTimeout — it persists the sleep across Worker restarts.