Cloudflare Workers Reference Sheet

Just a guy who loves to write code and watch anime.
Search for a command to run...

Just a guy who loves to write code and watch anime.
No comments yet. Be the first to comment.
Qualities that make outstanding builders.

Bipedal vs quadrupedal: how many legs This is about the number of legs the creature walks on. Bipedal. Two legs. Humans, ostriches, T-rex, kangaroos, most fantasy humanoids. Quadrupedal. Four legs. Do

Intro You hear "lerp" and "smoothstep" everywhere in game dev. They sound like math jargon. They're not. Both are small tools that do the same job: smoothly move from one value to another. The problem

What is Kinematics Kinematics is the math field. It's the study of how things move without worrying about forces (which would be dynamics). FK and IK are the two branches: forward kinematics and inver

Intro Textures are usually the biggest cost in a 3D scene. Memory, bandwidth, and load time all get eaten by them. Resizing them is the obvious lever. There's more. This post is about the less obvious

Workers Runtime: V8 isolates (not Node.js) running on Cloudflare's edge network
Cold start: <1ms vs 100ms+ for containers
Web APIs only (no fs, process.env)
Each request is isolated and stateless
Basic Structure:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
// Your logic here
return new Response('Hello World');
}
}
Request Object:
const url = new URL(request.url);
const method = request.method; // GET, POST, etc.
const headers = request.headers;
const body = await request.json(); // or .text()
// Query parameters
const userId = url.searchParams.get('userId'); // ?userId=123
Response Object:
// Simple text
return new Response('Hello');
// JSON with headers
return new Response(JSON.stringify({data: 'value'}), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
// Error response
return new Response(JSON.stringify({error: 'Bad request'}), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const url = new URL(request.url);
const path = url.pathname;
const method = request.method;
if (path === '/api/users' && method === 'GET') {
return new Response(JSON.stringify([{id: 1, name: 'Alice'}]), {
headers: { 'Content-Type': 'application/json' }
});
}
if (path === '/api/users' && method === 'POST') {
const userData = await request.json();
// Validation
if (!userData.name) {
return new Response(JSON.stringify({error: 'Name required'}), {
status: 400,
headers: { 'Content-Type': 'application/json' }
});
}
// Process...
return new Response(JSON.stringify({id: 123, ...userData}), {
status: 201,
headers: { 'Content-Type': 'application/json' }
});
}
return new Response('Not Found', { status: 404 });
}
}
wrangler.toml:
name = "my-worker"
compatibility_date = "2024-01-01"
# Non-secret environment variables
[vars]
API_URL = "https://api.example.com"
DEBUG = "true"
Secrets (sensitive data):
# Set secrets via CLI
wrangler secret put API_KEY
wrangler secret put DATABASE_PASSWORD
Using in code:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const apiKey = env.API_KEY; // secret
const apiUrl = env.API_URL; // regular env var
return new Response(`Using ${apiUrl}`);
}
}
TypeScript setup:
# Generate types for your specific Worker config
pnpm wrangler types
Add to tsconfig.json:
{
"compilerOptions": {
"types": ["./worker-configuration.d.ts"]
}
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
try {
// Call external API
const response = await fetch('https://api.example.com/data', {
method: 'POST',
headers: {
'Authorization': `Bearer ${env.API_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ query: 'example' })
});
if (!response.ok) {
return new Response(JSON.stringify({error: 'External API failed'}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
const data = await response.json();
// Transform and return
return new Response(JSON.stringify({
result: data.someField,
timestamp: Date.now()
}), {
headers: { 'Content-Type': 'application/json' }
});
} catch (error) {
return new Response(JSON.stringify({error: 'Request failed'}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
}
Cache API (like a persistent Map<string, Response>):
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const cache = caches.default; // or await caches.open('my-cache')
const cacheKey = 'weather-london';
// Try cache first
const cachedResponse = await cache.match(cacheKey);
if (cachedResponse) {
return cachedResponse;
}
// Cache miss - fetch fresh data
const freshResponse = await fetch(`https://api.weather.com?key=${env.API_KEY}`);
const data = await freshResponse.json();
const response = new Response(JSON.stringify(data), {
headers: {
'Content-Type': 'application/json',
'Cache-Control': 'max-age=300' // Browser caches for 5 min
}
});
// Store in Cloudflare cache (background)
ctx.waitUntil(cache.put(cacheKey, response.clone()));
return response;
}
}
Key concepts:
caches.default = global cache, caches.open('name') = named cache
response.clone() = needed because Response can only be read once
ctx.waitUntil() = keep Worker alive for background task, don't block response
Cache-Control header = browser caching, separate from caches API
// Middleware functions return Response to stop, null to continue
async function corsMiddleware(request: Request): Promise<Response | null> {
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE',
'Access-Control-Allow-Headers': 'Content-Type, Authorization'
}
});
}
return null;
}
async function authMiddleware(request: Request): Promise<Response | null> {
const authHeader = request.headers.get('Authorization');
if (!authHeader?.startsWith('Bearer ')) {
return new Response(JSON.stringify({error: 'Unauthorized'}), {
status: 401,
headers: { 'Content-Type': 'application/json' }
});
}
return null;
}
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
// Run middleware chain
const middlewares = [corsMiddleware];
for (const middleware of middlewares) {
const response = await middleware(request);
if (response) return response;
}
// Protected routes
const url = new URL(request.url);
if (url.pathname.startsWith('/api/protected/')) {
const authResponse = await authMiddleware(request);
if (authResponse) return authResponse;
}
// Your routes...
return new Response('OK');
}
}
For large datasets or real-time data:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const stream = new ReadableStream({
async start(controller) {
for (let i = 0; i < 10000; i++) {
// Each line is a separate JSON object
const chunk = JSON.stringify({id: i, data: `Item ${i}`}) + '\n';
controller.enqueue(new TextEncoder().encode(chunk));
// Yield occasionally
if (i % 100 === 0) {
await new Promise(resolve => setTimeout(resolve, 0));
}
}
controller.close();
}
});
return new Response(stream, {
headers: {
'Content-Type': 'application/x-ndjson', // Newline-delimited JSON
'Transfer-Encoding': 'chunked'
}
});
}
}
Error handling & logging:
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
const startTime = Date.now();
try {
// Your logic...
const response = new Response(JSON.stringify({success: true}), {
headers: { 'Content-Type': 'application/json' }
});
// Success metrics
console.log(`Success: ${request.method} ${new URL(request.url).pathname} - ${Date.now() - startTime}ms`);
return response;
} catch (error) {
console.error(`Error: ${request.method} ${request.url}`, error);
return new Response(JSON.stringify({error: 'Internal Server Error'}), {
status: 500,
headers: { 'Content-Type': 'application/json' }
});
}
}
}
Simple rate limiting:
const rateLimits = new Map<string, {count: number; resetTime: number}>();
function isRateLimited(ip: string, limit: number, windowMs: number): boolean {
const now = Date.now();
const current = rateLimits.get(ip);
// No data or window expired - reset
if (!current || now > current.resetTime) {
rateLimits.set(ip, {count: 1, resetTime: now + windowMs});
return false;
}
// Hit limit
if (current.count >= limit) {
return true;
}
// Increment and allow
current.count++;
return false;
}
Stateless: Variables don't persist between requests
Web APIs: Use fetch, Request, Response, URL - not Node.js APIs
Secrets vs Env Vars: Secrets via CLI, regular config in wrangler.toml
TypeScript: Run wrangler types after config changes
Caching: caches API for persistence, ctx.waitUntil() for background tasks
Rate Limiting: Implement your own, resets on each deployment (use KV for persistence)
# Deploy to production
wrangler deploy
# Deploy to staging
wrangler deploy --env staging
# View logs
wrangler tail