Cloudflare Workers is a serverless platform for running JavaScript/TypeScript code on Cloudflare's Edge servers worldwide. Code runs in the data center closest to the user, with no cold start.
Free Workers Plan
| Limit | Free | Paid ($5/mo) |
|---|---|---|
| Requests/day | 100,000 | 10M included |
| CPU time | 10 ms | 30 ms (default) |
| Workers | 30 | Unlimited |
Your First Worker
// Simple Worker — responds to all requests
export default {
async fetch(request, env) {
const url = new URL(request.url);
// Redirect old → new
if (url.pathname === '/old-page') {
return Response.redirect('https://example.com/new-page', 301);
}
// Add security headers
const response = await fetch(request);
const newResponse = new Response(response.body, response);
newResponse.headers.set('X-Frame-Options', 'DENY');
newResponse.headers.set('X-Content-Type-Options', 'nosniff');
return newResponse;
}
};
Deploying via Wrangler CLI
# Install Wrangler
npm install -g wrangler
# Log in
wrangler login
# Create the project
wrangler init my-worker
# Deploy
wrangler deploy
Useful Worker Examples
- Geo-redirect — redirect users to the localized version of a site by country
- A/B testing — randomly split traffic between versions
- Response transformation — modify HTML on the fly without a deploy
- Security headers — add CSP and HSTS to every response
- API rate limiting — throttle requests with logic in the Worker
Workers compared to a traditional backend
| Criterion | Cloudflare Workers | Regular server/VPS |
|---|---|---|
| Cold start | Practically none | Not applicable (the process is already running) |
| Where the code runs | The data center closest to the user | A single region |
| Filesystem access | None | Full |
| Long background jobs | Limited by CPU time | No platform limit |
| State between requests | Needs Workers KV/Durable Objects | Process memory, files, a database |
Breaking down Workers errors
Error 1101: Worker threw exception
An unhandled exception in the Worker's code — most often accessing an undefined variable, a Promise rejected without a .catch(), or an invalid attempt to read the request body (for example, reading request.body twice, when it can only be read once). Check logs with wrangler tail in real time or in Dashboard → Workers → Logs.
Error 1102: Worker exceeded resource limits
The Worker went over the CPU-time limit on the free plan, or got stuck in an infinite loop. Unlike a classic server timeout, this counts active CPU execution time, not time spent waiting for a response from an external API — a long fetch to a slow backend does not by itself eat into this limit.
Verifying the Worker works
# Watch the Worker's live logs
wrangler tail my-worker
# Check that the Worker actually handles the route
curl -I https://example.com/old-page
# Expected: HTTP/2 301 and a location header coming from the Worker's code
When Workers do not fit
- You need persistent filesystem access or to run OS-level binary dependencies — a Worker runs in an isolated V8 sandbox with no filesystem and without the full Node.js API.
- You need long background computations (minutes, not milliseconds) — a regular server or a job queue with a worker on a VPS fits better.
- You need to store and serve large files from the Worker itself — for that, a Worker reaches out to R2 through bindings instead of storing data inside itself.
A Worker gets access to environment variables and secrets through the env object passed into the fetch function. Secrets (API keys, tokens) are set with wrangler secret put NAME and never end up in plain text in the code or the repository — unlike ordinary variables defined in wrangler.toml.
Local debugging before deploying is done with wrangler dev — it spins up the Worker on your local machine with an emulated Cloudflare environment, including Workers KV and R2 bindings, so you do not have to deploy every change to production just to test it.
The "script startup exceeded CPU time limit" error differs from Error 1102 in that it is not about handling a request but about the module's own startup — it is usually caused by heavy top-level initialization in the file (for example, synchronously parsing a large JSON blob at startup), which should be moved inside the request handler or cached between calls.
Several Workers can be linked together through Service Bindings — one Worker calls another directly, without an HTTP request over the internet, with minimal latency, which is handy for splitting a large project into modules without extra cost.