Cloudflare Workers let you run JavaScript (or TypeScript!) at the edge, right on Cloudflare’s network, instead of in a traditional server.

Let’s build a simple worker that fetches data from an external API and returns it. This is a common use case: imagine you want to serve real-time stock prices or weather data without hitting your own backend.

First, we need a wrangler.toml file to configure our worker. wrangler is Cloudflare’s command-line tool for developing and deploying Workers.

name = "my-edge-api"
main = "dist/index.js"
compatibility_date = "2023-09-01"

The name is just an identifier. main points to the compiled JavaScript output. compatibility_date ensures your Worker runs with a specific set of Cloudflare runtime features, so you know what to expect.

Now, let’s write the TypeScript. Create a file named src/index.ts:

export interface Env {}

export default {
  async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
    const url = new URL(request.url);

    // Example: Proxying a request to an external API
    if (url.pathname === "/weather") {
      const city = url.searchParams.get("city") || "London"; // Default to London if no city is provided
      const apiKey = "YOUR_OPENWEATHER_API_KEY"; // Replace with your actual API key
      const weatherApiUrl = `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${apiKey}&units=metric`;

      try {
        const response = await fetch(weatherApiUrl);
        if (!response.ok) {
          return new Response(`Error fetching weather: ${response.statusText}`, { status: response.status });
        }
        const weatherData = await response.json();
        return new Response(JSON.stringify(weatherData), {
          headers: { "Content-Type": "application/json" },
        });
      } catch (error) {
        console.error("Fetch error:", error);
        return new Response("Internal Server Error", { status: 500 });
      }
    }

    // Handle other routes or return a default response
    return new Response("Hello from Cloudflare Workers!", {
      headers: { "Content-Type": "text/plain" },
    });
  },
};

To run this locally, you’ll need to install wrangler (npm install -g wrangler) and then run wrangler dev. This command will build your TypeScript, start a local development server, and proxy requests to your Worker. You can then visit http://localhost:8787/weather?city=Paris in your browser to see it in action.

The fetch event handler is the heart of a Worker. It receives the incoming Request object, an Env object (which we’ll get to), and an ExecutionContext. The Env object is where you can bind variables, secrets, or KV namespaces. The ExecutionContext provides methods like waitUntil to keep asynchronous tasks running after a response has been sent.

When you make a request to your Worker, Cloudflare routes it to the nearest edge location. The Worker code then executes in that location. For our /weather route, we’re taking the city parameter from the URL, constructing a request to the OpenWeatherMap API, and then returning the JSON response from that API back to the client, all from the edge.

The request object is a standard Web API Request object, and the Response object is a standard Web API Response object. This means you can use familiar JavaScript APIs like fetch, Headers, URL, etc., directly within your Worker.

To deploy this, you’d run wrangler deploy. Cloudflare then hosts your Worker code on its global network. When a user makes a request to your Worker’s domain (e.g., my-edge-api.your-subdomain.workers.dev), Cloudflare directs it to the closest data center, executes your code there, and returns the response.

The Env interface is where you declare what you’re binding to your worker. For instance, if you wanted to use Cloudflare KV (Key-Value store), you’d declare it like this:

interface Env {
  MY_KV_NAMESPACE: KVNamespace;
}

And then in wrangler.toml:

[[kv_namespaces]]
binding = "MY_KV_NAMESPACE"
id = "your-kv-namespace-id"

This allows you to access env.MY_KV_NAMESPACE within your Worker code, enabling fast, edge-served data retrieval without external API calls.

A subtle but powerful aspect of Workers is their ability to intercept and modify requests before they reach your origin server, or even replace the origin entirely. This means you can implement authentication, A/B testing, content personalization, or even route traffic based on complex logic, all without touching your primary application.

When you use fetch within a Worker to call another API, you’re not making a request from your own server to that API. You’re making a request from Cloudflare’s edge network to that API. This can significantly reduce latency for users globally and bypass certain network restrictions.

The ExecutionContext’s waitUntil method is crucial for tasks that need to complete after the response is sent, like logging or sending analytics. If you simply initiated an asynchronous operation (like another fetch) and didn’t waitUntil it, the Worker might exit before the operation completes, and the data would be lost.

The env object can also be populated with secrets, which are encrypted environment variables managed by Cloudflare. You can bind these in wrangler.toml and access them securely in your Worker code, like env.MY_SECRET_API_KEY.

The next step is to explore custom routing and middleware patterns within Workers to build more complex edge applications.

Want structured learning?

Take the full Cloudflare course →