Why we don't use custom domains for Cloudflare Workers (but sorta do)

Using a Cloudflare Worker for static pages costs money. Not much money, but still, not free. Cloudflare Pages is free on every request, so it makes sense to use that whenever possible. The thing is, you can't use a "custom domain" for a Worker, and then use the same custom domain for a Pages project later.

But.. you can use a custom domain for a Pages project, and add a Workers route on that same custom domain! This requires you have a Pages project ready to deploy on day 1 though, and is a bit of a pain to spend time deploying something that isn't even functional yet; our team generally develops our APIs with Workers first, and then sometime later deploys a frontend with Pages.

So, our approach is the following:

First, we create a AAAA record pointing to 100:: with the name of the custom domain we want to use eventually for our Cloudflare Pages project.

Then, begin our development cycle using a Worker. We always bind our routes to a more specific path than just /*, as later down the road we want to have a Cloudflare Pages project listening on that same domain! I'm a fan of /api/symver/* to keep it simple and easier to introduce new API versions to handle changes without risking breaking existing Workers in production.

name = "auth-worker-dev"
main = "./src/index.ts"
compatibility_date = "2023-08-14"
workers_dev = false

[vars]
ENVIRONMENT = "dev"

[env.production]
name = "auth-worker"
routes = [
  { pattern = "https://auth.ai.moda/api/v0.0.1/*", zone_name = "ai.moda" },
]

[env.production.vars]
ENVIRONMENT = "production"

Sometime in the far, far future, we have a frontend ready to deploy! We just delete the AAAA record that's pointing to 100::. Now, we deploy that sweet $0 per request static Cloudflare Pages project to our custom domain.

No changes needed on our Worker, it "just works" because we had planned for this situation ahead of time! 🎉