edge-patterns
Edge Computing patterns: Cloudflare Workers (Durable Objects, KV, D1, R2, Wrangler), Vercel Edge Middleware (geo-routing, A/B testing, Edge Config), Deno Deploy, edge runtime constraints (no fs/child_process, bundle limits), streaming responses, edge caching (Cache API, stale-while-revalidate), and testing with Miniflare.
Best use case
edge-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.
Edge Computing patterns: Cloudflare Workers (Durable Objects, KV, D1, R2, Wrangler), Vercel Edge Middleware (geo-routing, A/B testing, Edge Config), Deno Deploy, edge runtime constraints (no fs/child_process, bundle limits), streaming responses, edge caching (Cache API, stale-while-revalidate), and testing with Miniflare.
Teams using edge-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.
When to use this skill
- You want a reusable workflow that can be run more than once with consistent structure.
When not to use this skill
- You only need a quick one-off answer and do not need a reusable workflow.
- You cannot install or maintain the underlying files, dependencies, or repository context.
Installation
Claude Code / Cursor / Codex
Manual Installation
- Download SKILL.md from GitHub
- Place it in
.claude/skills/edge-patterns/SKILL.mdinside your project - Restart your AI agent — it will auto-discover the skill
How edge-patterns Compares
| Feature / Agent | edge-patterns | Standard Approach |
|---|---|---|
| Platform Support | Not specified | Limited / Varies |
| Context Awareness | High | Baseline |
| Installation Complexity | Unknown | N/A |
Frequently Asked Questions
What does this skill do?
Edge Computing patterns: Cloudflare Workers (Durable Objects, KV, D1, R2, Wrangler), Vercel Edge Middleware (geo-routing, A/B testing, Edge Config), Deno Deploy, edge runtime constraints (no fs/child_process, bundle limits), streaming responses, edge caching (Cache API, stale-while-revalidate), and testing with Miniflare.
Where can I find the source code?
You can find the source code on GitHub using the link provided at the top of the page.
SKILL.md Source
# Edge Patterns
Reference for building on edge runtimes — Cloudflare Workers, Vercel Edge, and Deno Deploy.
## When to Activate
- Building Cloudflare Workers or Pages Functions
- Writing Vercel Edge Middleware
- Deploying to Deno Deploy
- Debugging "not supported in edge runtime" errors
- Implementing geo-routing, A/B testing, or auth at the edge
- Setting up edge caching strategies
- Migrating a Node.js API route to an edge-compatible runtime to reduce cold-start latency
- Designing stateful edge logic using Durable Objects or Deno KV
- Choosing between Cloudflare, Vercel Edge, and Deno Deploy for a new globally distributed service
---
## Edge Runtime Constraints
Edge runtimes execute in V8 isolates — not Node.js. Key differences:
| Feature | Node.js | Edge Runtime |
|---------|---------|--------------|
| File system | `fs` module | ❌ Not available |
| Child processes | `child_process` | ❌ Not available |
| TCP sockets | `net`, `dgram` | ❌ Not available |
| Native modules | `node-gyp` bindings | ❌ Not available |
| npm packages | All | Only Web-API compatible |
| Bundle size | Unlimited | Cloudflare: 1MB / Vercel: 4MB |
| CPU time | Unlimited | Cloudflare: 50ms / Vercel: 25s wall |
| Cold starts | Seconds | Milliseconds (isolate reuse) |
**Available Web Standard APIs:**
- `fetch`, `Request`, `Response`, `Headers`
- `URL`, `URLSearchParams`
- `crypto.subtle` (Web Crypto API)
- `ReadableStream`, `WritableStream`, `TransformStream`
- `TextEncoder`, `TextDecoder`
- `setTimeout`, `setInterval` (limited in Workers)
- `Blob`, `FormData`
---
## Cloudflare Workers
### Worker Anatomy
```typescript
// src/index.ts
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
// env — bound resources (KV, D1, R2, secrets)
// ctx — lifecycle methods (waitUntil, passThroughOnException)
const url = new URL(request.url);
if (url.pathname === '/api/health') {
return Response.json({ status: 'ok' });
}
return new Response('Not Found', { status: 404 });
},
};
// Type bindings (generated by wrangler)
interface Env {
MY_KV: KVNamespace;
MY_DB: D1Database;
MY_BUCKET: R2Bucket;
MY_SECRET: string; // from wrangler.toml [vars] or Secrets
}
```
### wrangler.toml
```toml
name = "my-worker"
main = "src/index.ts"
compatibility_date = "2024-01-01"
[[kv_namespaces]]
binding = "MY_KV"
id = "abc123"
preview_id = "def456"
[[d1_databases]]
binding = "MY_DB"
database_name = "my-db"
database_id = "uuid-here"
[[r2_buckets]]
binding = "MY_BUCKET"
bucket_name = "my-bucket"
[vars]
ENVIRONMENT = "production"
```
### KV (Key-Value Store)
```typescript
// Write
await env.MY_KV.put('user:123', JSON.stringify(user), {
expirationTtl: 3600, // seconds
});
// Read
const raw = await env.MY_KV.get('user:123');
const user = raw ? JSON.parse(raw) : null;
// Read as JSON (shorthand)
const user = await env.MY_KV.get<User>('user:123', 'json');
// Delete
await env.MY_KV.delete('user:123');
// List keys
const { keys, list_complete } = await env.MY_KV.list({ prefix: 'user:' });
```
### D1 (SQLite at Edge)
```typescript
// Query
const { results } = await env.MY_DB.prepare(
'SELECT * FROM users WHERE id = ?'
).bind(userId).all<User>();
// Insert
const { success } = await env.MY_DB.prepare(
'INSERT INTO users (name, email) VALUES (?, ?)'
).bind(name, email).run();
// Batch (transactional)
const [create, notify] = await env.MY_DB.batch([
env.MY_DB.prepare('INSERT INTO users (name) VALUES (?)').bind(name),
env.MY_DB.prepare('INSERT INTO events (type, user) VALUES (?, ?)').bind('created', name),
]);
```
### R2 (Object Storage)
```typescript
// Upload
await env.MY_BUCKET.put(key, request.body, {
httpMetadata: { contentType: 'image/png' },
customMetadata: { uploadedBy: userId },
});
// Download
const object = await env.MY_BUCKET.get(key);
if (!object) return new Response('Not Found', { status: 404 });
return new Response(object.body, {
headers: {
'Content-Type': object.httpMetadata?.contentType ?? 'application/octet-stream',
'ETag': object.etag,
},
});
```
### Durable Objects (Stateful Edge)
```typescript
// Durable Object class — co-located storage + compute
export class SessionRoom {
private state: DurableObjectState;
private sessions: Map<string, WebSocket> = new Map();
constructor(state: DurableObjectState, env: Env) {
this.state = state;
// Hibernatable WebSocket API — don't hold connections during idle
this.state.acceptWebSocket(/* ... */);
}
async fetch(request: Request): Promise<Response> {
const { pathname } = new URL(request.url);
if (pathname === '/websocket') {
const pair = new WebSocketPair();
this.state.acceptWebSocket(pair[1]);
return new Response(null, { status: 101, webSocket: pair[0] });
}
// Durable storage — persists across invocations
const count = (await this.state.storage.get<number>('count') ?? 0) + 1;
await this.state.storage.put('count', count);
return Response.json({ count });
}
webSocketMessage(ws: WebSocket, message: string) {
// Broadcast to all connected clients
for (const session of this.state.getWebSockets()) {
session.send(message);
}
}
}
// wrangler.toml
// [[durable_objects.bindings]]
// name = "SESSION_ROOM"
// class_name = "SessionRoom"
```
### waitUntil — Background Tasks
```typescript
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext) {
const response = await handleRequest(request, env);
// Run after response is sent — doesn't block the response
ctx.waitUntil(logAnalytics(request, response, env));
ctx.waitUntil(updateCache(request, env));
return response;
},
};
```
### Wrangler Dev Workflow
```bash
# Local dev (runs in Workerd, same runtime as production)
wrangler dev
# Deploy to production
wrangler deploy
# Deploy to staging
wrangler deploy --env staging
# Tail production logs
wrangler tail
# D1 migrations
wrangler d1 migrations create my-db add-users-table
wrangler d1 migrations apply my-db
# KV operations
wrangler kv key put --binding=MY_KV "key" "value"
wrangler kv key get --binding=MY_KV "key"
```
---
## Vercel Edge Middleware
```typescript
// middleware.ts — runs before every matched request
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
const { pathname, searchParams } = request.nextUrl;
// Geo-based routing
const country = request.geo?.country ?? 'US';
if (pathname === '/pricing' && country === 'DE') {
return NextResponse.rewrite(new URL('/pricing/eu', request.url));
}
// A/B testing
const bucket = request.cookies.get('ab-bucket')?.value
?? (Math.random() < 0.5 ? 'a' : 'b');
const response = NextResponse.next();
response.cookies.set('ab-bucket', bucket, { maxAge: 86400 });
if (bucket === 'b') {
response.headers.set('x-experiment', 'variant-b');
}
return response;
}
// Only run middleware on these paths
export const config = {
matcher: [
'/pricing/:path*',
'/checkout/:path*',
'/((?!api|_next|static|favicon).*)',
],
};
```
### Edge Config (Feature Flags at Edge)
```typescript
import { get } from '@vercel/edge-config';
export async function middleware(request: NextRequest) {
const maintenanceMode = await get<boolean>('maintenance_mode');
if (maintenanceMode) {
return NextResponse.rewrite(new URL('/maintenance', request.url));
}
return NextResponse.next();
}
```
```bash
# Update without deployment
vercel env pull .env.local
vercel edge-config update '{"maintenance_mode": true}'
```
---
## Deno Deploy
```typescript
// main.ts — Deno-native edge function
Deno.serve(async (req) => {
const url = new URL(req.url);
if (url.pathname === '/api/hello') {
return Response.json({ message: 'Hello from Deno Deploy!' });
}
return new Response('Not Found', { status: 404 });
});
```
### Deno KV
```typescript
const kv = await Deno.openKv();
// Set
await kv.set(['users', userId], { name, email }, { expireIn: 3600_000 });
// Get
const entry = await kv.get<User>(['users', userId]);
const user = entry.value;
// Atomic operation
const result = await kv.atomic()
.check({ key: ['counter'], versionstamp: null })
.set(['counter'], 0)
.commit();
```
### Deploy via GitHub Actions
```yaml
name: Deploy to Deno Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- uses: denoland/deployctl@v1
with:
project: my-deno-project
entrypoint: main.ts
```
---
For streaming responses (TransformStream, Server-Sent Events), edge caching (Cache API, stale-while-revalidate), Miniflare testing, and common mistakes, see skill `edge-patterns-advanced`.
## Reference
- `serverless-patterns` — Cold starts, Step Functions, Lambda Powertools, idempotency
- `deployment-patterns` — Docker, CI/CD, rollback strategies
- `wasm-patterns` — Run Rust WASM in Cloudflare WorkersRelated Skills
zero-trust-patterns
Zero-Trust security patterns — mTLS between microservices (Istio/SPIFFE), SPIRE workload identity, OPA/Envoy authorization, NetworkPolicy default-deny-all, short-lived credentials, service mesh security, and Kubernetes RBAC hardening.
webrtc-patterns
WebRTC patterns — peer connection setup, ICE/STUN/TURN configuration, signaling server design, SFU vs mesh topology, screen sharing, media track management, and reconnect/ICE restart handling.
webhook-patterns
Webhook patterns for receiving, verifying (HMAC), and idempotently processing third-party events. Covers Stripe, GitHub, and generic webhook patterns, delivery guarantees, retry handling, and testing.
wasm-patterns
WebAssembly patterns: wasm-pack, wasm-bindgen (JS↔Wasm interop), WASI, Component Model, wasm-opt, Rust-to-WASM compilation, JS integration (web workers, streaming instantiation), and production deployment (CDN, Content-Type headers).
ux-micro-patterns
UX micro-patterns for every product state: Empty States, Loading States (skeleton screens, spinners, optimistic UI), Error States, Success States, Confirmation Dialogs, Onboarding Flows, and Progressive Disclosure. These patterns apply to every feature — done wrong, they're the biggest source of user confusion.
typescript-patterns
TypeScript patterns — type system best practices, strict mode, utility types, generics, discriminated unions, error handling with Result types, and module organization. Core patterns for production TypeScript.
typescript-patterns-advanced
Advanced TypeScript — mapped types, template literal types, conditional types, infer, type guards, decorators, async patterns, testing with Vitest/Jest, and performance. Extends typescript-patterns.
typescript-monorepo-patterns
TypeScript monorepo patterns with Turborepo + pnpm workspaces. Covers package structure, shared configs, task pipeline caching, build orchestration, and publishing strategy.
terraform-patterns
Infrastructure as Code with Terraform — project structure, remote state, modules, workspace strategy, AWS/GCP patterns, CI/CD integration, and security hardening. The standard for managing production infrastructure.
swiftui-patterns
SwiftUI architecture patterns, state management with @Observable, view composition, navigation, performance optimization, and modern iOS/macOS UI best practices.
swift-patterns
Core Swift patterns — value vs reference types, protocols, generics, optionals, Result, error handling, Codable, and module organization. Foundation for all Swift development.
swift-patterns-advanced
Advanced Swift patterns — property wrappers, result builders, Combine basics, opaque & existential types, macro system, advanced generics, and performance optimization. Extends swift-patterns.