This demo runs entirely on Cloudflare's edge network — no origin server, no containers, no load balancers. Every component you see in the pipeline is a distinct Cloudflare primitive, wired together using platform-native features.
Browser │ fetch() from JS — session key in query param, never in browser URL ▼ DNS → DDoS Protection → WAF → CDN ← Cloudflare network layer (automatic) │ ▼ Entrypoint Worker (main-worker.klym.workers.dev) │ ├─── RPC ──▶ Rate Limiter Worker ──▶ Durable Object (persistent counter) │ │ │ allowed / blocked │ ├─── RPC ──▶ Rewriter Worker │ │ │ ├─── RPC ──▶ Normalize URL Worker (lang prefix, path canonicalization) │ │ │ rewritten URL + request ID │ └─── fetch ▶ Origin Worker (demo HTML response) │ ▼ Browser ← headers carry pipeline trace, rewritten URL, rate-limit state
klym.net. The custom domain edge-demo.klym.net is a CNAME proxied through Cloudflare — the origin IP is never exposed.Each Worker is a separate deployable unit with its own wrangler.toml. They run in V8 isolates — not containers — so cold starts are sub-millisecond and there is no per-instance billing.
main-worker. The only Worker that is publicly addressable — all others are internal.RateLimiterWorker (WorkerEntrypoint) exposes typed RPC methods to the Entrypoint, and a RateLimiterDO (DurableObject) owns the persistent counter.checkLimit(key) and resetLimit(key). It resolves the DO stub via idFromName(key) and delegates the actual check to the DO.blockConcurrencyWhile in its constructor loads the persisted counter before any request is handled, preventing concurrent cold-starts from racing to read 0. Every increment is written to DO storage immediately, so the counter survives isolate eviction./old/*, /legacy/*, /v1/*) and short-circuits with a redirect. Otherwise calls Normalize URL and generates a request ID.Accept-Language if the path doesn't already have one.en, fr, de, es, ja.fetch() calls to the Entrypoint from the browser, then animates the trace data from response headers.All inter-worker calls use Service Bindings — not HTTP. The call stays on Cloudflare's internal network, adds zero network latency, and is billed as a single request.
// wrangler.toml — declare the binding [[services]] binding = "RATE_LIMITER" service = "rate-limiter-worker" entrypoint = "RateLimiterWorker" // TypeScript — call the remote method as if it were local const { allowed, remaining } = await env.RATE_LIMITER.checkLimit(cookieId);
Workers RPC requires the callee to extend WorkerEntrypoint and expose public async methods. Cloudflare generates the type-safe stub automatically from the exported class — no schema, no codegen step.
wrangler.toml at deploy time. The binding name becomes a typed property on env. No URLs, no auth tokens, no network hops.WorkerEntrypoint class. Requires compatibility_date ≥ 2024-04-03. Arguments and return values are serialized transparently.Workers are stateless by design — each request may land in a different isolate, anywhere in Cloudflare's network. Durable Objects solve this by giving you a single-threaded actor with persistent storage that all isolates coordinate through.
RATE_LIMITER_DO.idFromName(cookieId) maps each session to exactly one Durable Object instance worldwide. All requests for that session hit the same actor.ctx.storage.put('count', this.count) persists the counter to DO storage after every increment. The value survives isolate eviction.resetLimit() RPC. This makes the demo deterministic — requests 1–10 always pass, 11+ always block.