cloudflare-workflows
from jezweb/claude-skills
Skills for Claude Code CLI such as full stack dev Cloudflare, React, Tailwind v4, and AI integrations.
npx skills add https://github.com/jezweb/claude-skills --skill cloudflare-workflowsSKILL.md
Cloudflare Workflows
Status: Production Ready ✅ (GA since April 2025) Last Updated: 2026-01-09 Dependencies: cloudflare-worker-base (for Worker setup) Latest Versions: wrangler@4.58.0, @cloudflare/workers-types@4.20260109.0
Recent Updates (2025):
- April 2025: Workflows GA release - waitForEvent API, Vitest testing, CPU time metrics, 4,500 concurrent instances
- October 2025: Instance creation rate 10x faster (100/sec), concurrency increased to 10,000
- 2025 Limits: Max steps 1,024, state persistence 1MB/step (100MB-1GB per instance), event payloads 1MB, CPU time 5 min max
- Testing: cloudflare:test module with introspectWorkflowInstance, disableSleeps, mockStepResult, mockEvent modifiers
- Platform: Waiting instances don't count toward concurrency, retention 3-30 days, subrequests 50-1,000
Quick Start (5 Minutes)
# 1. Scaffold project
npm create cloudflare@latest my-workflow -- --template cloudflare/workflows-starter --git --deploy false
cd my-workflow
# 2. Configure wrangler.jsonc
{
"name": "my-workflow",
"main": "src/index.ts",
"compatibility_date": "2025-11-25",
"workflows": [{
"name": "my-workflow",
"binding": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}]
}
# 3. Create workflow (src/index.ts)
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
const result = await step.do('process', async () => { /* work */ });
await step.sleep('wait', '1 hour');
await step.do('continue', async () => { /* more work */ });
}
}
# 4. Deploy and test
npm run deploy
npx wrangler workflows instances list my-workflow
CRITICAL: Extends WorkflowEntrypoint, implements run() with step methods, bindings in wrangler.jsonc
Known Issues Prevention
This skill prevents 12 documented errors with Cloudflare Workflows.
Issue #1: waitForEvent Skips Events After Timeout in Local Dev
Error: Events sent after a waitForEvent() timeout are ignored in subsequent waitForEvent() calls
Environment: Local development (wrangler dev) only - works correctly in production
Source: GitHub Issue #11740
Why It Happens: Bug in miniflare that was fixed in production (May 2025) but not ported to local emulator. After a timeout, the event queue becomes corrupted for that instance.
Prevention:
- Test waitForEvent timeout scenarios in production/staging, not local dev
- Avoid chaining multiple
waitForEvent()calls where timeouts are expected
Example of Bug:
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
for (let i = 0; i < 3; i++) {
try {
const evt = await step.waitForEvent(`wait-${i}`, {
type: 'user-action',
timeout: '5 seconds'
});
console.log(`Iteration ${i}: Received event`);
} catch {
console.log(`Iteration ${i}: Timeout`);
}
}
}
}
// In wrangler dev:
// - Iteration 1: ✅ receives event
// - Iteration 2: ⏱️ times out (expected)
// - Iteration 3: ❌ does not receive event (BUG - event is sent but ignored)
Status: Known bug, fix pending for miniflare.
Issue #2: getPlatformProxy() Fails With Workflow Bindings
Error: MiniflareCoreError [ERR_RUNTIME_FAILURE]: The Workers runtime failed to start
Message: Worker's binding refers to service with named entrypoint, but service has no such entrypoint
Source: GitHub Issue #9402
Why It Happens: getPlatformProxy() from wrangler package doesn't support Workflow bindings (similar to how it handles Durable Objects). This blocks Next.js integration and local CLI scripts.
Prevention:
- Option 1: Comment out workflow bindings when using
getPlatformProxy() - Option 2: Create separate
wrangler.cli.jsoncwithout workflows for CLI scripts - Option 3: Access workflow bindings directly via deployed worker, not proxy
// Workaround: Separate config for CLI scripts
// wrangler.cli.jsonc (no workflows)
{
"name": "my-worker",
"main": "src/index.ts",
"compatibility_date": "2025-01-20"
// workflows commented out
}
// Use in script:
import { getPlatformProxy } from 'wrangler';
const { env } = await getPlatformProxy({ configPath: './wrangler.cli.jsonc' });
Status: Known limitation, fix planned (filter workflows similar to DOs).
Issue #3: Workflow Instance Lost After Immediate Redirect (Local Dev)
Error: Instance ID returned but instance.not_found when queried
Environment: Local development (wrangler dev) only - works correctly in production
Source: [GitHub Issue #10806](https://github.com/cloudflare/work
...