Cloudflare
Workers
Pages
Deploy
Roteamento

Workers and Pages: deployment, routing and what each model hides

Preview automatic deployments per branch are the operational difference of Pages that Workers do not replicate natively — and this detail changes the code review flow.

Workers and Pages: deployment, routing and what each model hides

When a team adopts Cloudflare Workers, the first deployment is trivial: wrangler deploy, that's it, the script is live. When another team adopts Pages, the first deployment is also trivial: connect the GitHub repository, configure the build command, that's it. The problem appears when the two coexist in the same zone, when you need a preview per branch, or when someone needs to audit what is running in production without accessing the dashboard.

How Workers deploy

The central artifact of a Workers project is wrangler.toml. It contains routes, bindings, environment variables, compatibility limits and environments. A typical production/staging deployment looks like this in the same file:

name = "minha-api" main = "src/index.ts" compatibility_date = "2024-09-23" [[routes]] pattern = "api.exemplo.com/*" zone_name = "exemplo.com" [env.staging] name = "minha-api-staging" [[env.staging.routes]] pattern = "api-staging.exemplo.com/*" zone_name = "exemplo.com"

This is versioned configuration in code, reviewable in pull requests, traceable in Git history. Any route or binding change goes through the same code review process.

wrangler deploy --env staging deploys the script as a separate Worker (minha-api-staging), with its own routes and bindings. Environments in Workers are distinct Workers — not variants of the same deployment.

How Pages deploys

Pages works via git push. You connect a repository, define the build command and output directory on the dashboard, and each push to the main branch triggers a pipeline: clone, install, build, upload the assets to the CDN. The pipeline runs up to 500 builds/month on the free plan and 5,000/month on the paid plan ($20/month).

The big operational difference: each push to any branch other than the main one generates an automatic preview deployment with a unique URL in the format hash-branch.seuprojet.pages.dev. You open a pull request, Cloudflare comments on the PR with the preview URL. The product team tests the URL before approving the merge. Workers has no native equivalent for this.

The symmetric limitation: Pages build settings — build command, environment variables, Node version — are on the dashboard, not in the code file. To date, there is no full wrangler.toml support for Pages. This means that build configuration changes do not go through pull requests and are not in Git history. For teams that require a full infrastructure audit trail, this is a real friction.

Routing and the route collision trap

Workers use route patterns linked to a zone. The api.exemplo.com/v1/* pattern captures all requests for this path and delivers them to the corresponding script. If two different Workers try to register the same pattern in the same zone, the second deploy fails with a conflict error.

Pages uses a dedicated subdomain (*.pages.dev) or a custom domain linked to the project. When you use a custom domain in Pages, Cloudflare creates an internal Worker that serves the assets and routes them to the Functions. This internal Worker occupies the domain routes.

The concrete problem: you have a Pages project in app.exemplo.com and want to add a separate Worker to process webhooks in app.exemplo.com/webhooks. It does not give. Pages routes already capture app.exemplo.com/*. The solution is to move the webhooks handler to a Pages Function in /functions/webhooks.ts, or use a separate subdomain (webhooks.exemplo.com) with an independent Worker.

The routing precedence within Pages follows a fixed order: _redirects is processed first, then _headers, then the Functions in /functions, and lastly the static assets. This means that a Function in /functions/blog/[slug].ts has priority over a static file in /blog/qualquer-coisa.html — which might be surprising if you generated static pages with the same path.

Page Environments and what’s missing

Pages has the concept of production and preview environments. Production is the main branch; any other branch generates a preview. You can configure environment variables separated by environment on the dashboard.

What Pages doesn't have: multiple named environments with different build configurations. Workers allows wrangler deploy --env staging with a completely different set of bindings and variables. In Pages, if you want a staging environment with a different D1 database, you create a separate Pages project and manage the synchronization between the two manually.

For teams that work with strict staging — [separate database, sandbox API keys, distinct feature flags — this limitation is significant and generally pushes these workloads to Workers.

How wrangler.toml goes (partially) to Pages

Cloudflare announced experimental support in 2020 for configuring Pages Functions bindings — KV namespaces, D1 databases, environment variables. This solves part of the audit trail problem: the bindings stay in the code. But the build pipeline (command, output directory, Node version) is still on the dashboard.

The current state is partial. Those who need 100% code configuration today use Workers with assets served via R2 + Cache API, giving up the free Pages CDN. This is a real trade-off that is worth calculating before making the decision.

What to evaluate before deciding

The Pages deployment model offers two concrete assets: integrated build pipeline (no external CI to assemble) and automatic preview deployments per branch. For design and product teams reviewing features before merging, branch preview speeds up the review cycle measurably.

Workers offers auditable code configuration from day one, named environments with distinct bindings, and support for non-HTTP triggers (cron, queues, email) that Pages doesn't have. For APIs or services without a visual component that need rigorous staging, Workers structured with well-organized wrangler.toml are operationally cleaner.

Route collision between projects in the same zone is the most common problem for teams that start with Pages and then try to add isolated Workers. The correct mental mapping: a custom domain in Pages is like a Workers that occupies the wildcard of that domain. Anything else you want on that domain needs to live within the Pages project.

Also read