Smithery Logo
MCPsSkillsDocsPricing
Login
Smithery Logo

Accelerating the Agent Economy

Resources

DocumentationPrivacy PolicySystem Status

Company

PricingAboutBlog

Connect

© 2026 Smithery. All rights reserved.

    neversight

    cloudflare-workflows

    neversight/cloudflare-workflows
    DevOps
    2
    1 installs

    About

    SKILL.md

    Install

    Install via Skills CLI

    or add to your agent
    • Claude Code
      Claude Code
    • Codex
      Codex
    • OpenClaw
      OpenClaw
    • Cursor
      Cursor
    • Amp
      Amp
    • GitHub Copilot
      GitHub Copilot
    • Gemini CLI
      Gemini CLI
    • Kilo Code
      Kilo Code
    • Junie
      Junie
    • Replit
      Replit
    • Windsurf
      Windsurf
    • Cline
      Cline
    • Continue
      Continue
    • OpenCode
      OpenCode
    • OpenHands
      OpenHands
    • Roo Code
      Roo Code
    • Augment
      Augment
    • Goose
      Goose
    • Trae
      Trae
    • Zencoder
      Zencoder
    • Antigravity
      Antigravity
    ├─
    ├─
    └─

    About

    Cloudflare Workflows durable execution playbook: multi-step orchestration, state persistence, retries, sleep/scheduling, waitForEvent, external events, bindings, lifecycle management, limits, pricing...

    SKILL.md

    Cloudflare Workflows

    Workflows provide durable multi-step execution for Workers. Steps persist state, survive restarts, support retries, and can sleep for days.


    Quick Start

    Create Workflow

    // src/index.ts
    import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";
    
    interface Env {
      MY_WORKFLOW: Workflow;
    }
    
    interface Params {
      userId: string;
      action: string;
    }
    
    export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
      async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
        const user = await step.do("fetch user", async () => {
          const resp = await fetch(`https://api.example.com/users/${event.payload.userId}`);
          return resp.json();
        });
    
        await step.sleep("wait before processing", "1 hour");
    
        const result = await step.do("process action", async () => {
          return { processed: true, user: user.id };
        });
    
        return result; // Available in instance.status().output
      }
    }
    
    export default {
      async fetch(request: Request, env: Env): Promise<Response> {
        const instance = await env.MY_WORKFLOW.create({
          params: { userId: "123", action: "activate" },
        });
        return Response.json({ instanceId: instance.id });
      },
    };
    

    wrangler.jsonc

    {
      "name": "my-workflow-worker",
      "main": "src/index.ts",
      "workflows": [
        {
          "name": "my-workflow",
          "binding": "MY_WORKFLOW",
          "class_name": "MyWorkflow"
        }
      ]
    }
    

    Deploy

    npx wrangler deploy
    

    Core Concepts

    WorkflowEntrypoint

    export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
      async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
        // Workflow logic with steps
        return optionalResult;
      }
    }
    

    WorkflowEvent

    interface WorkflowEvent<T> {
      payload: Readonly<T>; // Immutable input params
      timestamp: Date; // Creation time
      instanceId: string; // Unique instance ID
    }
    

    Warning: Event payload is immutable. Changes are NOT persisted across steps. Return state from steps instead.

    WorkflowStep

    interface WorkflowStep {
      do<T>(name: string, callback: () => Promise<T>): Promise<T>;
      do<T>(name: string, config: StepConfig, callback: () => Promise<T>): Promise<T>;
      sleep(name: string, duration: Duration): Promise<void>;
      sleepUntil(name: string, timestamp: Date | number): Promise<void>;
      waitForEvent<T>(name: string, options: WaitOptions): Promise<T>;
    }
    

    See api.md for full type definitions.


    Steps

    Basic Step

    const result = await step.do("step name", async () => {
      const response = await fetch("https://api.example.com/data");
      return response.json(); // State persisted
    });
    

    Step with Config

    const data = await step.do(
      "call external API",
      {
        retries: {
          limit: 10,
          delay: "30 seconds",
          backoff: "exponential",
        },
        timeout: "5 minutes",
      },
      async () => {
        return await externalApiCall();
      }
    );
    

    Default Step Config

    const defaultConfig = {
      retries: {
        limit: 5,
        delay: 10000, // 10 seconds
        backoff: "exponential",
      },
      timeout: "10 minutes",
    };
    
    Option Type Default Description
    retries.limit number 5 Max attempts (use Infinity for unlimited)
    retries.delay string/number 10000 Delay between retries
    retries.backoff string exponential constant, linear, exponential
    timeout string/number 10 min Per-attempt timeout

    Sleep & Scheduling

    Relative Sleep

    await step.sleep("wait before retry", "1 hour");
    await step.sleep("short pause", 5000); // 5 seconds (ms)
    

    Duration units: second, minute, hour, day, week, month, year.

    Sleep Until Date

    const targetDate = new Date("2024-12-31T00:00:00Z");
    await step.sleepUntil("wait until new year", targetDate);
    
    // Or with timestamp
    await step.sleepUntil("wait until launch", Date.parse("24 Oct 2024 13:00:00 UTC"));
    

    Maximum sleep: 365 days.

    Note: step.sleep and step.sleepUntil do NOT count towards the 1024 steps limit.


    Wait for Events

    Wait in Workflow

    const approval = await step.waitForEvent<{ approved: boolean }>("wait for approval", {
      type: "user_approval",
      timeout: "7 days",
    });
    
    if (approval.approved) {
      await step.do("proceed", async () => {
        /* ... */
      });
    }
    

    Default timeout: 24 hours.

    Timeout behavior: Throws error and fails instance. Use try-catch to continue:

    try {
      const event = await step.waitForEvent("optional event", { type: "update", timeout: "1 hour" });
    } catch (e) {
      // Continue without event
    }
    

    Send Event from Worker

    export default {
      async fetch(request: Request, env: Env): Promise<Response> {
        const { instanceId, approved } = await request.json();
        const instance = await env.MY_WORKFLOW.get(instanceId);
    
        await instance.sendEvent({
          type: "user_approval", // Must match waitForEvent type
          payload: { approved },
        });
    
        return new Response("Event sent");
      },
    };
    

    Event buffering: Events can be sent before Workflow reaches waitForEvent. They are buffered and delivered when the matching step executes.

    See events.md for REST API.


    Error Handling

    NonRetryableError

    import { NonRetryableError } from "cloudflare:workflows";
    
    await step.do("validate input", async () => {
      if (!event.payload.data) {
        throw new NonRetryableError("Missing required data");
      }
      return event.payload.data;
    });
    

    Catch and Continue

    try {
      await step.do("risky operation", async () => {
        await riskyApiCall();
      });
    } catch (error) {
      await step.do("handle failure", async () => {
        await sendAlertEmail(error.message);
      });
    }
    

    Workflow States

    Status Description
    queued Waiting to start
    running Actively executing
    paused Manually paused
    waiting Sleeping or waiting for event
    waitingForPause Pause requested, waiting to take effect
    complete Successfully finished
    errored Failed (uncaught exception or retry limit)
    terminated Manually terminated

    Workflow Bindings

    Create Instance

    const instance = await env.MY_WORKFLOW.create({
      id: "order-12345", // Optional custom ID (max 100 chars)
      params: { orderId: 12345 },
    });
    console.log(instance.id);
    

    Create Batch

    const instances = await env.MY_WORKFLOW.createBatch([{ params: { userId: "1" } }, { params: { userId: "2" } }, { params: { userId: "3" } }]);
    // Up to 100 instances per batch
    

    Get Instance

    const instance = await env.MY_WORKFLOW.get("order-12345");
    

    Instance Methods

    await instance.pause(); // Pause execution
    await instance.resume(); // Resume paused
    await instance.terminate(); // Stop permanently
    await instance.restart(); // Restart from beginning
    
    const status = await instance.status();
    console.log(status.status); // "running", "complete", etc.
    console.log(status.output); // Return value from run()
    console.log(status.error); // { name, message } if errored
    
    await instance.sendEvent({
      type: "approval",
      payload: { approved: true },
    });
    

    Rules of Workflows

    ✅ DO

    • Make steps granular and self-contained
    • Return state from steps (only way to persist)
    • Name steps deterministically
    • await all step calls
    • Keep step return values under 1 MiB
    • Use idempotent operations in steps
    • Base conditions on event.payload or step returns

    ❌ DON'T

    • Store state outside steps (lost on restart)
    • Mutate event.payload (changes not persisted)
    • Use non-deterministic step names (Date.now(), Math.random())
    • Skip await on step calls
    • Put entire logic in one step
    • Call multiple unrelated services in one step
    • Do heavy CPU work in single step

    Step State Persistence

    // ✅ Good: Return state from step
    const userData = await step.do("fetch user", async () => {
      return await fetchUser(userId);
    });
    
    // ❌ Bad: State stored outside step (lost on restart)
    let userData;
    await step.do("fetch user", async () => {
      userData = await fetchUser(userId); // Will be lost!
    });
    

    Wrangler Commands

    # List instances
    wrangler workflows instances list my-workflow
    
    # Describe instance
    wrangler workflows instances describe my-workflow --id <instance-id>
    
    # Terminate instance
    wrangler workflows instances terminate my-workflow --id <instance-id>
    
    # Trigger new instance
    wrangler workflows trigger my-workflow --params '{"key": "value"}'
    
    # Delete Workflow
    wrangler workflows delete my-workflow
    

    Limits

    Feature Free Paid
    CPU time per step 10 ms 30 sec (max 5 min)
    Wall clock per step Unlimited Unlimited
    State per step 1 MiB 1 MiB
    Event payload 1 MiB 1 MiB
    Total state per instance 100 MB 1 GB
    Max sleep duration 365 days 365 days
    Max steps per Workflow 1024 1024
    Concurrent instances 25 10,000
    Instance creation rate 100/sec 100/sec
    Queued instances 100,000 1,000,000
    Subrequests per instance 50/req 1000/req
    Instance ID length 100 chars 100 chars
    Retention (completed) 3 days 30 days

    Note: Instances in waiting state (sleeping, waiting for event) do NOT count against concurrency limits.

    Increase CPU Limit

    {
      "limits": {
        "cpu_ms": 300000 // 5 minutes
      }
    }
    

    Pricing

    Based on Workers Standard pricing:

    Metric Free Paid
    Requests 100K/day (shared) 10M/mo included, +$0.30/M
    CPU time 10 ms/invocation 30M ms/mo included, +$0.02/M ms
    Storage 1 GB 1 GB included, +$0.20/GB-mo

    Storage notes:

    • Calculated across all instances (running, sleeping, completed)
    • Deleting instances frees storage (updates within minutes)
    • Free plan: instance errors if storage limit reached

    See pricing.md for details.


    Prohibitions

    • ❌ Do not mutate event.payload (changes not persisted)
    • ❌ Do not store state outside steps
    • ❌ Do not use non-deterministic step names
    • ❌ Do not exceed 1 MiB per step return
    • ❌ Do not skip await on step calls
    • ❌ Do not rely on in-memory state between steps

    References

    • api.md — Full API reference
    • events.md — Event handling and REST API
    • patterns.md — Saga, approval, reminders
    • pricing.md — Billing details

    Cross-References (Skills)

    • cloudflare-workers — Worker development
    • cloudflare-queues — Message queue integration
    • cloudflare-r2 — Large state storage
    • cloudflare-kv — Key-value references
    Recommended Servers
    Vercel
    Vercel
    Kernel
    Kernel
    Google Calendar
    Google Calendar
    Repository
    neversight/skills_feed