Cloudflare
Workers
Pages
Capacidades
Edge

What only Workers do, what only Pages do and where the two meet

The architecture that uses Workers and Pages correctly doesn't choose between the two — it uses Pages for CDN and co-located API, Workers for everything non-HTTP.

What only Workers do, what only Pages do and where the two meet

Platform documentation tends to describe each product in isolation, from the best possible angle. This creates a reading where Workers seems more powerful than Pages and Pages seems simpler than Workers. Neither reading is correct. They have genuinely unique capabilities in each direction — and a wide overlap zone where the difference is only in deployment model.

What only Workers have

Cron triggers are the most relevant primitive that does not exist in Pages. In wrangler.toml:

[triggers] crons = ["0 3 * * *", "*/15 * * * *"]

This records two crons: one at 3am every day, another every 15 minutes. The corresponding handler is method scheduled of the object exported by the Worker. Pages does not have this primitive. It's not a runtime limitation — it's a product decision. If you need periodic execution, it's a freelance Worker.

Queue consumers operate in a similar way. Cloudflare Queues allows you to queue messages and process them asynchronously. The consumer — the Worker that reads from the queue — is configured at wrangler.toml with [[queues.consumers]]. Pages Functions cannot be queue consumers; can only publish messages to queues via binding.

Email Workers receive emails directly. You configure an email route in Cloudflare to point to a Worker, and the Worker receives the email as an object with a sender, recipient, headers, and body. This allows you to process bounces, parse invoice receipts, or route emails to different queues — all without your own email server. Pages does not support this trigger.

Workers for Platforms is the multi-tenancy mechanism where SaaS users can deploy their own Workers within the operator's account. The operator uses a Dispatch Worker that receives requests and forwards them to the correct tenant script. It is an infrastructure primitive for platforms that need to execute arbitrary user code with guaranteed isolation. Exclusive to Workers.

TCP Sockets (in beta) allow direct TCP connections from a Worker — useful for connecting to databases that do not have an HTTP API, such as PostgreSQL or Redis without Upstash. Still evolving, but without equivalent in Pages.

Durable Object Alarms deserve separate mention from Durable Objects in general. DOs work in both, but alarms — timers that wake up a specific DO at a defined time — are a scheduling primitive that complements cron triggers for cases with state per entity (scheduling a reminder per user, for example). Available in both runtimes, but the orchestration normally starts from a Worker with a cron or queue trigger.

What only Pages has

Hosting static assets at zero cost per request is the most underrated capability of Pages and the most expensive to replicate outside of Pages. When you deploy a Pages project, the static files (HTML, CSS, JavaScript, images, fonts) are distributed via Cloudflare's global CDN. Requests for these assets do not go through the Workers runtime — they are served directly from the CDN edge, without triggering any computing logic, without counting as an invocation, with no cost per request beyond the Pages plan.

Pages' free plan includes unlimited CDN requests. The paid plan costs $20/month and adds 5,000 builds/month and up to 5 concurrent builds. For a site with tens of millions of monthly pageviews, this lack of cost per static request is a significant billing advantage over any architecture based on pure Workers.

Preview automatic deployments per branch are the second difference. Each push to a non-main branch generates a unique URL in the format hash-branch.seuprojeto.pages.dev, with assets and Functions running together. No additional configuration, no CI scripts to write. Workers doesn't replicate this natively — you need to set up the "branch deployment" flow manually in your CI.

The integrated build pipeline is also unique. Pages detects the framework (Next.js, Astro, SvelteKit, Nuxt, Hugo, Gatsby), configures the build defaults, and runs the build process in an isolated environment with each push. For Workers, the build is the responsibility of your CI — which is more flexible, but means more configuration to maintain.

Conventions _redirects and _headers allow you to configure redirects and HTTP headers for static assets via plain text files in the project root, without code. Useful for URL, HSTS, Content Security Policy and cache header migrations. Workers can implement the same with code, but it is more verbose.

What do the two have in common

The V8 runtime is identical. The limits are the same: 128MB of memory (hard), 10MB of compressed script on the paid plan, 30s of CPU per request, 1,000 subrequests per invocation. Any code that runs in Workers runs in Pages Functions without changing.

Data bindings are shared: D1 (SQLite at the edge), KV (distributed key-value), R2 (object storage), Durable Objects (coordination-consistent state), AI (model inference at the edge). You can have a D1 database accessed by both Pages Functions and an autonomous Worker configured on the same wrangler.toml with the binding pointing to the same database ID.

Service Bindings work both ways: a Pages Function can call a standalone Worker directly via internal binding, without public network latency. A Worker can call another Worker. The call is a normal fetch() against binding, but routed internally on the Cloudflare network.

The architecture that uses each one in the right place

The pattern that emerges from projects that use Workers and Pages correctly has three layers. The first is the Pages project: it serves the SPA or build-generated website, with static assets on the CDN at no cost per request. The API routes are in /functions/api/ — Pages Functions co-located with the frontend, with branch preview included, accessing D1 and KV for application data.

The second layer is Workers for asynchronous jobs: standalone scripts with cron triggers for scheduled processing, Queue consumers for asynchronous work decoupled from the HTTP critical path, Email Workers for email processing. These Workers access the same data bindings as the Pages project — the same D1 database, the same KV namespace.

The third layer is communication between them via Service Bindings. A Pages Function that needs heavy processing calls the specialized Worker directly, without external HTTP. The Cron Worker that needs to trigger a notification can call the sending Pages Function via Service Binding.

This architecture is not theoretical. This is what happens when you use each primitive where it solves the problem with lower operational cost: Pages free CDN for assets, same runtime for the co-located API, standalone Workers for the triggers that Pages doesn't support.

The decision map

The question that organizes the decision is: what triggers this code? If it is an HTTP request and the code lives together with a frontend, Pages Functions. If it is an HTTP request but the project does not have a frontend — pure API service — Workers with configuration in wrangler.toml. If it's anything other than HTTP — scheduled time, queue message, incoming email — Workers have no alternative.

Both sides of the table have capabilities that the other cannot replicate without additional cost or complexity. A decision that ignores this — using only Workers because you think it's more "serious", or just Pages because you think it's simpler — will hit a limit that requires refactoring sooner than necessary.

Also read