tech/cloudflare/workflows

WORKFLOWS

Cloudflare Workflows — durable multi-step execution.

production Cloudflare Workers (Paid, beta)
improves: tech/cloudflare

Cloudflare Workflows

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.

wrangler.toml

[[workflows]]
name = "brief-analysis"
binding = "BRIEF_WORKFLOW"
class_name = "BriefAnalysisWorkflow"

Workflow class

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);
    });
  }
}

Triggering a workflow from a Worker

// 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'

Common Gotchas

See Also