You can run code on Cloudflare’s edge network, right next to your users, using Edge Functions and Workers.
Let’s see it in action. Imagine you want to serve a personalized greeting based on the user’s country.
// workers/greeting.js
export default {
async fetch(request) {
const country = request.headers.get("CF-IPCountry");
let greeting = "Hello!";
if (country === "US") {
greeting = "Howdy!";
} else if (country === "GB") {
greeting = "Alright?";
}
return new Response(`${greeting} Welcome to our site!`);
},
};
To deploy this, you’d use the Wrangler CLI:
wrangler deploy workers/greeting.js
This deploys your greeting.js file to Cloudflare’s global network. Now, any request hitting your Cloudflare-proxied domain will first execute this Worker. The request object contains information about the incoming HTTP request, including headers like CF-IPCountry, which Cloudflare automatically adds. The Worker then constructs a new Response based on this information and sends it back to the user.
The real power comes from understanding how this fits into the broader request lifecycle. When a user requests a resource, their browser first performs a DNS lookup. If your domain is proxied through Cloudflare, the DNS resolution points to Cloudflare’s edge servers. The request then arrives at the nearest edge location. If you have an Edge Function or Worker configured for that route, it executes before the request is forwarded to your origin server (if it even needs to go to the origin at all). This allows you to intercept, modify, or completely handle requests at the edge.
You can control when your Worker runs using routes. When you deploy a Worker, you associate it with a specific route pattern. For example, you might configure a Worker to run on example.com/* to handle all requests, or on example.com/api/* to only handle API requests, or even example.com/images/*.jpg to only process image files. This routing is handled by Cloudflare’s edge configuration, not by your Worker code itself.
The fetch event handler is the core of a Worker. It receives a request object, which is a standard Web Fetch API Request object, and must return a Response object. This means you can use familiar Web APIs within your Workers. You can read request headers, modify them, inspect the request body, and construct custom responses. You can also make outgoing HTTP requests from your Worker using fetch, allowing you to interact with external APIs or your own origin servers.
The Cache API is also available within Workers, enabling you to cache responses at the edge. This dramatically improves performance by serving cached content directly from the nearest edge server without hitting your origin. For instance, you could cache API responses for a few minutes to reduce load on your backend.
// workers/cached-api.js
export default {
async fetch(request) {
const cache = caches.default;
let response = await cache.match(request);
if (!response) {
// Cache miss, fetch from origin
response = await fetch(request.url);
// Cache the response for 5 minutes
await cache.put(request, response.clone());
}
return response;
},
};
This simple Worker checks the cache first. If the response isn’t there, it fetches it from the origin, caches it, and then returns it.
The surprising thing about Workers is that they don’t just execute JavaScript; they run in a secure, isolated JavaScript runtime environment based on V8 isolates, not Node.js. This means you don’t have access to the Node.js APIs like fs or http. Instead, you work with a subset of Web APIs and Cloudflare-specific APIs. This design choice is crucial for security and cold-start performance, as isolates are much lighter and faster to spin up than traditional serverless containers.
The next step is understanding how to manage state across multiple Workers or persist data beyond the scope of a single request, which leads to exploring Workers KV and Durable Objects.