The answer. There are two ways to attach a hostname to a Worker and they answer different questions. A Custom Domain (pattern = "api.example.com", custom_domain = true) means the Worker is the origin: Cloudflare writes the DNS record, issues the certificate, and sends every path to the Worker. A Route (pattern = "shop.example.com/api/*", zone_name = "example.com") means the Worker runs in front of something that already answers on that hostname, so a proxied DNS record must exist first; without one you get ERR_NAME_NOT_RESOLVED, not a Worker error. Routes are matched most-specific-first, which is how one host can send /ingest/* to one Worker and /* to another. In our API Worker the domain is a Custom Domain while two narrow zone_name routes on the marketing host own only the Stripe checkout return path.
The pattern.
[env.production]
routes = [
{ pattern = "api.example.com", custom_domain = true }, # Worker is the origin
{ pattern = "www.example.com/subscription/success*", zone_name = "example.com" }, # in front of Webflow
]
No origin yet but need a route? Add a proxied placeholder record: AAAA shop.example.com 100::
Watch out.
- A Worker on a Custom Domain can be reached by
fetch()from another Worker on the same zone; a Worker on a Route cannot, which is one root of edge error 1042. - A Route whose pattern is just
/*on a zone you also use for Pages or Webflow silently captures that site too. Third-party SEO tools that install/*routes are the same hazard. wrangler deployadds routes but never removes ones it does not know about. Retired routes must be deleted in the dashboard or API.
Related: worker-fetch-own-zone-error-1042 · webflow-homepage-via-transform-rule-rewrite · service-bindings-call-a-private-worker-without-a-url