Compute

Workers

Workers is the compute block of the Cloudflare platform. Code that runs at the edge, close to your users, with no servers to manage and no cold starts. Some Workers handle HTTP requests; others run on a schedule, consume queues, or react to events. Either way, this site itself is a Worker.

// three demos on this page: static assets, request context, then HTML rewriting ↓

Worker request flow A browser sends a request to Cloudflare's edge. A Worker runs there, decides whether to answer directly or call storage, databases, APIs, or an origin server, then returns a response. browser visitor request worker runs at the edge fetch(request, env, ctx) backend KV · R2 · D1 · APIs request response fetch / read data Cloudflare edge can answer directly a Worker is the compute layer between the request and whatever comes next
// request flow through a Worker

Why Workers feel different

  • No cold starts. V8 isolates spin up in under a millisecond. There's no container to warm, no Lambda-style "first request is slow" tax.
  • Global by default. Code runs in 330+ cities. No regions to pick. The Worker that ran your request ran in the city closest to you.
  • Bindings replace SDK setup. Connect to KV, R2, D1, AI, or another Worker by declaring a binding in wrangler.jsonc. Your code reads env.KV.get("key") — credentials live in config, never in code. No client to instantiate, no API tokens to pass around.
  • CPU-time billing. A Worker that waits 30 seconds on an upstream API bills for the ~5ms of CPU it actually used.

Try it

Workers + Static Assets

The Worker serving this page is doing two jobs at once. It ran the code that built the HTML you're reading, and it served every static file the page needed — the CSS, the fonts, the favicon. Same deployment. Same wrangler.jsonc. No separate hosting, no CDN to configure.

You don't have to click anything to see this work. It already happened to get this page in front of you:

  • /workers — this HTML was rendered by src/pages/workers.ts inside the Worker.
  • /styles/main.css — the stylesheet was served from env.ASSETS, the same Worker's assets binding.
  • /fonts/general-sans/GeneralSans-Semibold.woff2 — the font you're reading was served the same way.

One Worker, one deployment, both jobs. That's the WSA model.

How Workers + Static Assets works

The assets block in wrangler.jsonc tells Cloudflare where the static files live and how the Worker should see them. The binding: "ASSETS" line exposes them on env.ASSETS so the Worker can hand off any request the page routes don't claim.

wrangler.jsonc
// wrangler.jsonc — the assets block
// that ships this page's HTML, CSS, fonts,
// and favicon alongside the Worker code.

"assets": {
  "directory": "./public",
  "binding": "ASSETS",
  "not_found_handling": "none"
}

In src/index.ts, the Worker checks page routes first. Anything unmatched is delegated to env.ASSETS, which serves the file from ./public (or returns a 404 the Worker can intercept).

src/index.ts
// src/index.ts — page routes are
// matched first; anything that doesn't
// match falls through to env.ASSETS.

if (pathname === "/workers") {
  return htmlResponse(renderLayout({ ... }));
}
// ...other page routes...

// Static asset fallback. The Worker hands
// the request to the assets binding, which
// serves the file (or returns 404).
const assetResponse = await env.ASSETS.fetch(request);
return assetResponse;

For new full-stack projects, this is the model Cloudflare recommends — even over Cloudflare Pages. One deployment, one set of bindings, one place to think about routing.

Try it

Request context

Workers are useful when a response should depend on the request itself: route visitors by country, redirect old URLs, vary content by device, or make bot-aware decisions before an origin sees traffic. Below is a live readout for your request, computed server-side by this Worker. Click refresh to make a new request and see the values update.

Colo
CMH
Country
US
City
Columbus
ASN
16509
AS Org
Anthropic, PBC
HTTP
HTTP/2
TLS
TLSv1.3
Bot Score
1
Render (ms)
0

How request context works

Every Worker handles requests through a fetch method. Cloudflare adds a cf object to the standard Web Request, giving your code edge-specific metadata like colo, country, TLS version, and ASN.

src/handlers/workers.ts
// /api/workers/fingerprint — read selected
// fields from the request.cf object Cloudflare
// attaches to every inbound request.

export function readFingerprint(request: Request) {
  const cf = request.cf;
  return {
    colo: cf?.colo ?? null,
    country: cf?.country ?? null,
    city: cf?.city ?? null,
    asn: cf?.asn != null ? String(cf.asn) : null,
    asOrganization: cf?.asOrganization ?? null,
    httpProtocol: cf?.httpProtocol ?? null,
    tlsVersion: cf?.tlsVersion ?? null,
  };
}

Try it

HTML rewriting

Workers can sit in front of an existing site and modify HTML on the way out. That can add security attributes to links, inject a temporary banner, rewrite docs URLs, or run a small A/B test without changing the origin app. The Worker below annotates every <a> and heading. Edit the input and try it.

How HTML rewriting works

HTMLRewriter is a Cloudflare-specific streaming HTML transformer. Register selectors, mutate matching elements as they pass through, and return the transformed response.

src/handlers/workers.ts
// /api/workers/rewrite — annotate anchors
// and headings via HTMLRewriter, Cloudflare's
// streaming HTML transformer.

const rewriter = new HTMLRewriter()
  .on("a", {
    element(el) {
      el.setAttribute("data-rewritten", "true");
      el.before("→ ", { html: false });
    },
  })
  .on("h1, h2, h3", {
    element(el) {
      el.before(`[${el.tagName}] `, { html: false });
    },
  });

const transformed = rewriter.transform(
  new Response(html, {
    headers: { "content-type": "text/html" },
  }),
);
return new Response(await transformed.text(), {
  headers: { "content-type": "text/html; charset=utf-8" },
});

When Workers is the right tool

  • HTTP at the edge — APIs, redirects, A/B tests, auth proxies
  • Anything that needs request context (geo, ASN, TLS) before your origin sees it
  • Streaming transforms — HTML, JSON, server-sent events
  • Full-stack apps — Worker + static assets in one deployment, replacing Pages for new projects
  • Scheduled jobs — Cron Triggers run your Worker on a schedule, no HTTP request needed
  • Queue consumers and event handlers — react to Queues, R2 uploads, AI Gateway events
  • The compute layer in front of your storage (KV, R2, D1) and AI (Workers AI)

For strongly-consistent state, reach for Durable Objects. For long-running, durable orchestration, look at Workflows. For a full Linux runtime, secure code execution, or anything that needs to run for many minutes, reach for Containers or Sandboxes. For anything else… a Worker is probably the right starting point.