Rate Limiter Demo
Native Workers Rate Limiting binding with 429 responses and usage visualization - protect APIs at the edge without Redis
Demonstrates the native Workers Rate Limiting binding. GET /limited enforces per-key limits and returns 429 with Retry-After when exceeded. GET /status shows configured limits and demo usage counters stored in KV.
Features
- GET /limited - Rate-limited endpoint (10 req / 60s per key)
- GET /status?key= - View limit config and usage counters
- 429 responses - Includes
Retry-Afterheader andRATE_LIMITEDcode - Per-key limiting - Defaults to client IP; override with
?key=
API Reference
GET /limited
Request the rate-limited resource.
key string (optional query)
Override rate limit key (max 128 chars). Defaults to CF-Connecting-IP.
Example Request
curl "https://your-worker.workers.dev/limited"
curl "https://your-worker.workers.dev/limited?key=demo-client"Success Response
{
"message": "Request allowed",
"key": "203.0.113.1",
"limit": 10,
"periodSeconds": 60
}Rate Limited Response (429)
{
"error": "Rate limit exceeded",
"code": "RATE_LIMITED",
"key": "203.0.113.1",
"retryAfterSeconds": 60
}Response includes header: Retry-After: 60
GET /status
View rate limit configuration and demo usage counters.
key string (optional query)
Key to inspect. Defaults to client IP.
Example Request
curl "https://your-worker.workers.dev/status?key=demo-client"Success Response
{
"key": "demo-client",
"config": { "limit": 10, "periodSeconds": 60 },
"usage": {
"key": "demo-client",
"allowed": 7,
"blocked": 3,
"lastSeen": "2025-06-20T12:00:00.000Z"
},
"note": "Native Rate Limiting binding enforces limits per PoP..."
}Use Cases
- Learn the Workers Rate Limiting binding (
limit()API) - Prototype API throttling before production WAF rules
- Demonstrate 429 + Retry-After client handling
Limitations
- Rate limits are enforced per PoP by the native binding
- KV usage counters are for demo visualization only (not authoritative)
- Configured limit: 10 requests per 60 seconds (see
wrangler.json)
Use in your project
Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/rate-limiter-demo.
import type { Env, UsageRecord } from "../types/env";function usageKey(key: string): string { return `usage:${key}`;}export async function recordUsage(env: Env, key: string, allowed: boolean): Promise<UsageRecord> { const existingRaw = await env.USAGE.get(usageKey(key)); const existing = existingRaw ? (JSON.parse(existingRaw) as UsageRecord) : { key, allowed: 0, blocked: 0, lastSeen: new Date().toISOString() }; const updated: UsageRecord = { ...existing, allowed: existing.allowed + (allowed ? 1 : 0), blocked: existing.blocked + (allowed ? 0 : 1), lastSeen: new Date().toISOString(), }; await env.USAGE.put(usageKey(key), JSON.stringify(updated), { expirationTtl: 3600 }); return updated;}export async function getUsage(env: Env, key: string): Promise<UsageRecord | null> { const raw = await env.USAGE.get(usageKey(key)); return raw ? (JSON.parse(raw) as UsageRecord) : null;}export function resolveClientKey(request: Request, override?: string | null): string { if (override?.trim()) return override.trim().slice(0, 128); const ip = request.headers.get("CF-Connecting-IP") ?? request.headers.get("X-Forwarded-For"); return ip?.split(",")[0]?.trim() || "anonymous";}export function validateKey(input: string | undefined | null): string | null { if (!input || typeof input !== "string") return null; const trimmed = input.trim(); if (!trimmed || trimmed.length > 128) return null; return trimmed;}Deployment
Configure KV
Create a KV namespace bound as USAGE. Rate limit binding is declared in wrangler.json.
Test rate limiting
for i in $(seq 1 12); do curl -s -o /dev/null -w "%{http_code}\n" "https://your-worker.workers.dev/limited"; doneLocal Development
cd apps/experiments/rate-limiter-demo
npm install
npm run devConfiguration
| Binding / setting | Purpose |
|---|---|
RATE_LIMITER | Native rate limiting (10 req / 60s) |
USAGE | KV namespace for demo usage counters |
Cloudflare Features Used
- Workers - Edge compute runtime
- Rate Limiting binding - Native per-key throttling
- Workers KV - Demo usage tracking