| license | Apache-2.0 |
| name | cloudflare-worker-dev |
| description | Cloudflare Workers, KV, Durable Objects, and edge computing development. Use for serverless APIs, caching, rate limiting, real-time features. Activate on "Workers", "KV", "Durable Objects", "wrangler", "edge function", "Cloudflare". NOT for Cloudflare Pages configuration (use deployment docs), DNS management, or general CDN settings. |
| allowed-tools | Read,Write,Edit,Bash,Grep,Glob |
| category | DevOps & Infrastructure |
| tags | ["cloudflare","workers","edge-computing","serverless","kv","caching","rate-limiting"] |
Cloudflare Workers Development
Build high-performance edge APIs with Workers, KV for caching, and Durable Objects for real-time coordination.
DECISION POINTS
Service Selection Decision Tree
Need real-time state consistency?
├── YES → Use Durable Objects
│ ├── Chat/collaboration → WebSocket pattern
│ ├── Counters/queues → Atomic operations
│ └── Session management → Per-user Objects
└── NO → Continue to storage decision
├── Need fast reads, eventual consistency OK?
│ ├── YES → Use KV
│ │ ├── Cache TTL < 1 hour → expirationTtl: 3600
│ │ ├── Config/sessions → expirationTtl: 86400
│ │ └── Long-term cache → expirationTtl: 604800
│ └── NO → Use external DB (D1/Postgres)
└── File storage needed?
└── YES → Use R2 (images, documents)
Geohash Precision vs Accuracy
Geographic scope?
├── City-level (10km radius) → 4-character geohash
├── Metro area (50km radius) → 3-character geohash
├── Regional (100km radius) → 2-character geohash
└── Country-level → Use country code instead
Cache hit rate priority?
├── HIGH → Use 2-3 character geohash (broader cache sharing)
└── PRECISION → Use 4-5 character geohash (location accuracy)
Rate Limiting Strategy
Rate limit scope?
├── Per IP → Use CF-Connecting-IP header
├── Per user → Use auth token/user ID
├── Per API key → Use Authorization header
└── Global → Use fixed key
Time window?
├── Burst protection (< 1 min) → Use in-memory counter
├── Short term (1-60 min) → Use KV with TTL
└── Long term (> 1 hour) → Use external storage
FAILURE MODES
CPU Timeout Spiral
Symptoms: Worker returns 1102 error code, logs show "CPU time limit exceeded"
Detection Rule: If logs contain "exceeded CPU time" or status 1102 responses
Root Cause: Synchronous operations blocking event loop (JSON parsing large payloads, complex loops)
Fix:
- Profile with
console.time() to find bottlenecks
- Stream large JSON parsing:
response.json() → ReadableStream
- Break loops with
await scheduler.wait(0) every 1000 iterations
- Cache expensive calculations in KV
KV Inconsistency Race
Symptoms: Stale data returned immediately after writes, cache "flapping" between values
Detection Rule: If read-after-write returns old value or cache hit rate drops unexpectedly
Root Cause: Reading KV immediately after write hits different edge nodes
Fix:
- Never read KV immediately after write for validation
- Return the value you just wrote:
await kv.put(key, data); return data;
- For consistency needs, use Durable Objects instead
- Add
X-Cache-Status header to debug cache behavior
Rate Limit Race Condition
Symptoms: Users get inconsistent rate limit responses, some bypass limits under load
Detection Rule: If rate limit counters drift from expected values or users report sporadic 429s
Root Cause: Multiple concurrent requests increment counter simultaneously
Fix:
- Use atomic increment pattern with KV metadata versioning
- Implement jitter: random 10-50ms delay before rate limit check
- Add circuit breaker: if KV fails, allow request but log for monitoring
- Use Durable Objects for strict rate limiting on critical endpoints
CORS Preflight Failure
Symptoms: Browser requests work in dev but fail in production, OPTIONS returns 404
Detection Rule: If seeing "CORS policy" errors in browser console or 404s on OPTIONS requests
Root Cause: Missing OPTIONS handler in route logic
Fix:
- Add explicit OPTIONS handler before all other routes
- Return 204 status with proper CORS headers
- Include all HTTP methods your API supports in Allow-Methods header
- Test with browser DevTools Network tab to verify preflight
Background Task Abandonment
Symptoms: Cache updates don't happen, cleanup tasks never run, inconsistent state
Detection Rule: If cache miss rates increase or background metrics stop updating
Root Cause: Using await instead of ctx.waitUntil() for background work
Fix:
- Wrap all background tasks in
ctx.waitUntil()
- Add logging inside background tasks to verify execution
- Set reasonable timeouts for background work (< 30s)
- Use scheduled triggers for critical maintenance tasks
WORKED EXAMPLES
Building a Location-Based Meeting Cache
Scenario: API needs to cache meeting data by geographic region with sub-second response times.
Step 1: Service Selection Decision
- Need real-time consistency? NO (eventual consistency acceptable for meeting data)
- Need fast reads? YES → Choose KV
- Geographic scope? Metro area (50km) → Use 3-character geohash
Step 2: Implementation
async function getMeetings(lat: number, lng: number, env: Env, ctx: ExecutionContext) {
const geohash = Geohash.encode(lat, lng, 3);
const cacheKey = `meetings:${geohash}`;
const cached = await env.MEETING_CACHE.get(cacheKey, 'json');
if (cached) {
return { data: cached, source: 'cache', geohash };
}
const meetings = await fetchFromAPI(lat, lng);
ctx.waitUntil(
env.MEETING_CACHE.put(cacheKey, JSON.stringify(meetings), {
expirationTtl: 3600,
metadata: { cachedAt: Date.now(), coords: `,` }
})
);
{ : meetings, : , geohash };
}
Expert vs Novice Decision Points:
- Novice: Uses exact coordinates as cache key → Low hit rate
- Expert: Uses geohash for geographic bucketing → High hit rate across nearby requests
- Novice: Awaits cache write → Slower response times
- Expert: Background cache write with waitUntil → Fast responses
Step 3: Rate Limiting Integration
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const ip = request.headers.get('CF-Connecting-IP') || 'unknown';
const rateCheck = await checkRateLimit(ip, env, { maxRequests: 100, windowSeconds: 3600 });
if (!rateCheck.allowed) {
return new Response('Rate limited', { status: 429 });
}
const url = new URL(request.url);
const lat = parseFloat(url.searchParams.get('lat') || '0');
const lng = parseFloat(url.searchParams.get('lng') || '0');
const result = await getMeetings(lat, lng, env, ctx);
(.(result.), {
: {
: ,
: result.,
: result.,
: rateCheck..()
}
});
}
};
QUALITY GATES
Deployment Readiness Checklist:
NOT-FOR BOUNDARIES
This skill should NOT be used for:
- Cloudflare Pages deployment → Use
static-site-deployment skill instead
- DNS record management → Use
cloudflare-dns-management skill instead
- CDN/proxy-only configuration → Use
cloudflare-cdn-config skill instead
- Workers AI/Vectorize → Use
ai-integration skill instead
- Large file processing (>100MB) → Use
batch-processing skill with external storage
- Long-running tasks (>30s CPU) → Use
background-job-processing skill instead
- Complex SQL operations → Use
database-optimization skill with dedicated DB
- Email sending → Use
email-service-integration skill instead
Delegate when:
- Static site needs deployment → Pages handles build/deploy pipeline better
- Complex database queries needed → D1 has SQL limitations, use external Postgres/MySQL
- Heavy computation required → Workers have CPU limits, use dedicated compute instances
- File uploads > 100MB → Use R2 direct upload patterns, not through Worker