You can serve Cloudflare Workers from a custom domain, but it’s not about pointing DNS records directly at the Worker itself; it’s about pointing DNS records at Cloudflare’s edge network, which then routes traffic to your Worker based on a configuration within your Cloudflare account.

Let’s see this in action. Imagine you have a Worker script that simply returns a static message.

// worker.js
export default {
  async fetch(request) {
    return new Response("Hello from my custom domain Worker!");
  }
};

You’ve deployed this to Cloudflare. Now, you want api.example.com to serve this Worker.

First, you need to add your domain (example.com) to Cloudflare and ensure its DNS is managed by Cloudflare. This is the foundational step. Once your domain is active in Cloudflare, navigate to the "Workers & Pages" section in your Cloudflare dashboard.

Click "Create Application" and choose "Create Worker." Give your Worker a name, for instance, my-custom-domain-worker. Paste your worker.js script into the editor.

Now, to associate api.example.com with this Worker, you go back to your domain’s settings in Cloudflare, under the "Workers & Pages" tab. Select your Worker. You’ll see an option to "Add Custom Domain." Click it.

In the "Custom Domain" field, enter api.example.com. Cloudflare will automatically create a CNAME record for you in your DNS settings. It will look something like this:

CNAME api.example.com cname.api.example.com

And then, Cloudflare internally maps cname.api.example.com to your Worker. You don’t manually create the cname.api.example.com record; Cloudflare handles it when you add the custom domain in the Worker settings.

If you were to curl api.example.com at this point, you’d see "Hello from my custom domain Worker!". The magic here is that Cloudflare’s edge servers intercept requests for api.example.com. They check their configuration, see that this hostname is mapped to my-custom-domain-worker, and then execute your Worker script before returning the response. The actual Worker code doesn’t "live" on api.example.com; it lives on Cloudflare’s distributed edge, and api.example.com is simply a pointer to that edge.

The problem this solves is serving dynamic content, or even just routing traffic intelligently, from a domain you own without needing to manage traditional origin servers for every subdomain. You get the benefits of Cloudflare’s global network, including low latency, DDoS protection, and SSL, all applied to your Worker’s execution.

Internally, Cloudflare uses a routing layer that maps incoming requests based on DNS records and Worker configurations. When a request for api.example.com hits an edge server, that server looks up the associated Worker. This lookup involves checking a global registry of Worker-to-hostname mappings. If a match is found, the request is processed by the Worker’s runtime environment (V8 Isolates) on that edge server. The Worker’s fetch handler receives the Request object, processes it, and returns a Response object, which is then sent back to the client.

The exact levers you control are primarily the Worker script itself and the hostname mapping. You can also configure routes within the Worker settings. For example, you could have api.example.com/users/* route to one Worker and api.example.com/products/* to another, or even use a single Worker to handle different paths based on request.url.

What most people don’t realize is that the Worker doesn’t inherently "know" it’s being served from api.example.com. It only receives the Request object. Information about the original hostname is available in request.headers.get('host'), but if you have multiple custom domains or routes pointing to the same Worker, you need to inspect this header or the request.url to differentiate.

The next concept you’ll encounter is handling different HTTP methods and request bodies within your Worker, or perhaps implementing more complex routing logic.

Want structured learning?

Take the full Cloudflare course →