Part 1: Understanding Cloudflare Workers & Edge Middleware

Introduction — The Rise of Edge Computing
In the last decade, we’ve witnessed a massive shift from monoliths → microservices → serverless. Each step moved compute closer to flexibility, but not necessarily closer to users.
Edge computing changes that. It allows you to run code within the CDN network itself, milliseconds from the user. Cloudflare Workers make this possible by letting developers run JavaScript and TypeScript code in more than 300 data centers globally.
Running logic at the edge improves latency, enhances security, reduces costs, and scales automatically without traditional server provisioning. In this series, we will build production-ready middleware for HTTP and WebSocket traffic. The focus will be on rate limiting, but the patterns we discuss will apply to caching, authentication, and logging.
What Are Cloudflare Workers?
Cloudflare Workers are small JavaScript or TypeScript programs that run inside V8 isolates the same sandbox used by Chrome and Node.js, but stripped down and optimized for edge execution.
When a request hits your domain, it passes through Cloudflare’s network. Your Worker can then inspect or modify the request, authenticate or rate-limit the client, cache responses, transform data, or proxy WebSocket connections before reaching your origin servers.
Workers start in less than one millisecond and can handle millions of requests concurrently. They are ideal for ultra-fast, high-scale logic that runs close to the user.
How Workers Differ from Lambda and Friends
| Feature | Cloudflare Worker | AWS Lambda | Vercel Functions |
| Startup Time | ~1 ms (no cold start) | 100-500 ms | 100-300 ms |
| Runtime | V8 Isolate (Web APIs) | Node.js Container | Node.js |
| Max CPU Time | 50 ms (default plan) | up to 15 min | 10 s |
| Deploy Scope | Global edge | Single region | Region + edge cache |
| State Model | Durable Objects & KV | DB / External | DB / External |
Workers are designed for short-lived, high-performance workloads. They are not suitable for long-running tasks or heavy compute operations.
The V8 Isolate Runtime ⚙️ - Browser DNA at the Edge
Because Cloudflare Workers run inside a V8 isolate, the environment is more like a browser than Node.js.
What Works:
Standard Web APIs such as
fetch,Request,Response,URL,Headers,FormData,ReadableStream, andCrypto.Modern ECMAScript syntax including
async/awaitand modules.Cloudflare bindings such as
KV,R2,Durable Objects,D1,Queues, andAIintegrations.
What Does Not Work:
Node.js-specific APIs such as fs, net, tls, dgram, path, os, cluster, and child_process are not available. Packages that depend on these will fail.
This means not all npm packages will work. Any library that depends on Node internals will break.
Alternatives and Patterns
| Node Package Type | Edge-Safe Alternative |
HTTP client (axios) | Native fetch API |
Router (express) | hono or itty-router |
| Cache / Storage | Cloudflare KV / R2 |
| Crypto helpers | WebCrypto API |
| Env config | Worker Env bindings / wrangler.toml |
A quick check: if the code runs in Chrome’s DevTools console, it probably runs in a Cloudflare Worker.
Why This Matters for Middleware Design
Building middleware on Workers means embracing Web APIs and message-based architecture, not Node servers.
Instead of spinning up a Redis client, you might use a Durable Object that acts as a distributed counter. Instead of file I/O, you rely on Cloudflare KV for persistence. Instead of Express middleware, you define lightweight fetch handlers.
These constraints lead to simpler, safer, and globally scalable patterns, but they also force you to design differently.
The Idea of Edge Middleware
Think of middleware as the logic between a user’s request and your origin response.
┌────────────────────┐
Client → │ Edge Middleware │ → Backend API
└────────────────────┘
▲
Logging, Auth,
Rate Limiting
At the edge, middleware can decide within milliseconds whether a request deserves to reach your backend or not.
Some of the benefits of this approach are:
Better Security: Bad actors can be dropped early, even before reaching your back-end service.
Improved Performance: Reduce round-trips to origin.
Cost: Save bandwidth and compute.
Observability: Capture metrics closer to users, which can be further exported to Loki/Grafana/Mimir.
When to Use Edge Middleware
Below are some real, production-ready workloads handled daily by Cloudflare Workers.
| Scenario | Edge Solution | Benefit |
| API rate limiting | Worker + Durable Object | Global throttling |
| Auth token check | Worker middleware | Drop unauthorized before origin |
| Request logging | Worker → Logs API | Low-latency telemetry |
| Feature flags | Worker KV lookup | Rollouts per region |
| WebSocket gateway | Worker + Durable Object hub | Real-time control at edge |
Why Edge Rate Limiting Beats Traditional Approaches
Traditional rate limiting relies on in-memory counters or Redis. This introduces latency and single points of failure.
Edge rate limiting solves this by:
Storing counters in Durable Objects, automatically sharded by user key.
Evaluating requests close to the user.
Providing consistent global enforcement per client.
This results in sub-millisecond enforcement with minimal backend dependency.
Durable Objects (DO)
Durable Objects are stateful actors that maintain consistent state across requests.
A Durable Object can:
Store data in memory.
Persist data between requests.
Receive messages via fetch().
Guarantee one instance per ID worldwide.
Each API key or client can have a dedicated Durable Object instance. This is ideal for token buckets, request counters, or WebSocket hubs.
+---------------------------+
| Durable Object: user_123 |
| tokens = 5 of 10 |
| lastRefill = 1699999999 |
+---------------------------+
Architecture Vision for This Series
┌────────────────────────────┐
│ Cloudflare Edge │
│ ┌────────────────────────┐ │
Client → → → → │ │ Worker (Middleware) │ │ → Backend
│ │ - Auth & Rate Limit │ │
│ │ - WS Proxy Gateway │ │
│ └────────────────────────┘ │
│ ┌────────────────────────┐ │
│ │ Durable Object(s) │ │
│ │ - Per-user counters │ │
│ │ - Token buckets │ │
│ └────────────────────────┘ │
└────────────────────────────┘
The beauty of this design is that it scales automatically — no central Redis, no replication nightmares, no cold starts.
Setting Up the Environment
- Install Wrangler
npm install -g wrangler
Confirm:
npx wrangler --version
Note: At the time of writing, Wrangler requires at least Node.js v20.0.0. Consider using a Node.js version manager such as nvm to switch node versions.
- Login to Cloudflare
npx wrangler login
- Initialize a Worker Project
npx wrangler init edge-middleware

Response to all prompts are shared in the screenshot above. Your file/folder structure should be similar to this:
.
├── node_modules\
├── package-lock.json
├── package.json
├── src
│ └── index.ts
├── test
│ ├── env.d.ts
│ ├── index.spec.ts
│ └── tsconfig.json
├── tsconfig.json
├── vitest.config.mts
├── worker-configuration.d.ts
└── wrangler.jsonc
We’ll define the RateLimiter Durable Object class in Part 2.
Your First Hello-World Worker
Try a simple fetch handler:
//src/index.ts
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
return new Response("Hello from Cloudflare worker", {
headers: { "content-type": "text/plain" },
});
},
} satisfies ExportedHandler<Env>;
Run locally:
npx wrangler dev
Visit http://localhost:8787 → you’ll see the response instantly.
Practice: Simple Edge Middleware
Let’s add basic validation before proxying to a backend:
//src/index.ts
export default {
async fetch(req: Request) {
const url = new URL(req.url);
if (!url.pathname.startsWith("/api")) {
return new Response("Forbidden", { status: 403 });
}
const backend = await fetch("https://api.yourbackend.com" + url.pathname, {
headers: req.headers,
method: req.method,
body: req.body,
});
const res = new Response(backend.body, backend);
res.headers.set("x-edge-checked", "true");
return res;
},
};
You’ve now written an edge gateway that can inspect, block, and modify traffic before it reaches your origin. For local testing, I’ll run a basic HTTP server locally and use that as my backend endpoint.
python3 -m http.server 8001
You can replace https://api.yourbackend.com in the src/index.ts with http://localhost:8001 if testing locally too.
Debugging and Local Testing
Wrangler provides a powerful local runtime which simulates the Cloudflare environment, including Durable Objects and bindings. You can get it started by running:
npx wrangler dev
Simulate requests:
for i in {1..10}; do curl -s -o /dev/null -w "%{http_code}\n" http://localhost:8787/api/test; done
Deployment
Deploying your worker to Cloudflare makes it globally accessible, and can be achieved by running:
npx wrangler deploy
Your Worker is instantly available and the link is displayed in the terminal, something like this: https://<your-project-id>.workers.dev. You can also add a custom domain to the worker via the Cloudflare worker dashboard.
Observability and Metrics
Cloudflare gives built-in analytics, but you can push custom metrics too:
Workers Logs API: stream structured logs.
Durable Object storage: aggregate usage per key.
Integrations: send logs to Grafana/Loki/Mimir (LGTM stack).
Wrangler tail: live-view logs during dev.
Since we interested in the live-view logs of the deployed worker, we can run:
npx wrangler tail
Closing Thoughts
Cloudflare Workers change how we think about deploying logic on the internet. Instead of running code on a single server or region, the platform pushes your logic to the edge, closer to every user. This makes Workers feel fast in practice, even when doing simple tasks like modifying headers, validating requests, or shaping traffic before it reaches your backend.
Because Workers run inside a V8 isolate, they follow a “browser-style” environment. This means you won’t have access to traditional Node.js modules, but you do get lightweight execution, instant cold starts, and a highly secure sandbox. Once you work within those boundaries, the platform becomes surprisingly flexible and powerful.
Part 1 focused on building an intuition for Workers and the concept of middleware at the edge. In Part 2, we move from ideas to implementation. We’ll build a practical HTTP rate limiter using Durable Objects, compare popular algorithms, and walk through how they behave in real-world workloads.
Next Up: [Part 2: Building an HTTP Rate Limiter with Durable Objects]

![Deploy and Access Flask App on Windows Server [No CGI]](/_next/image?url=https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1639120854833%2Ft8KDePUF_.png&w=3840&q=75)