Workers Services
Workers Services are the new building blocks for deploying applications on Cloudflare Workers. Workers Services are made of environments, which are scripts that can contain bindings to KV stores, Durable Objects, or even other services, as well as environment variables and secrets. Workers Services can have multiple environments and can set up pipelines for promoting a deployment from one environment to another.
Unlike a traditional Workers script, a Workers Service is composable, which allows Workers services to talk to each other; allowing you to develop new kinds of services like routers, middlewares, deployment managers, or traffic gateways. Workers Services also support multiple environments, allowing you to test changes in a preview environment, then promote those changes to production when you are ready – or execute your own custom deployment strategies.
Each Workers Service comes with a production environment and the ability to create or clone dozens of preview environments. Every aspect of an environment is overridable: the code, environment variables, and resource bindings, like KV namespaces and Durable Objects.
You can create and switch between environments in the dashboard:
- Go to Workers.
- Choose your Worker.
- Select production > Create environment.
Service environments
Wrangler supports an older version of environments. With Wrangler environments, you create custom contexts for your code to run in by adding keys to your wrangler.toml
file. Wrangler will then generate a separate Workers Service for each Wrangler environment. If you make a staging and production environment, for example, Wrangler will generate my-worker-staging
and my-worker-prod
.
Workers Service environments take a cleaner approach. You can create and edit environments directly in the dashboard:
- Log in to the Cloudflare dashboard.
- Select your Account.
- Go to Workers.
- Select your Workers Service.
- Select Quick edit.
Unlike Wrangler environments, Workers Service environments do not create extra Workers Services. They are, however, able to connect to their own KV stores and Durable Objects. The code for any environment can be changed directly in the dashboard via the quick editor:
- Go to Account Home.
- Go to Workers.
- Choose your Worker.
- Select Quick edit.
A common workflow is to create an environment for a test feature, edit the code via the quick editor until you are satisfied with it, and then promote it to production when the code is ready.
Each environment is resolvable at a unique hostname, which is automatically generated when you create or rename the environment. There is no wait after you deploy. Everything you need, like DNS records and SSL certificates, is ready seconds later. If you would like a more advanced setup, you can add custom routes from your domain to an environment.
Environment versions
Each environment in a Workers Service has its own version history. Every time there is a code change or an environment variable is updated, the version number of that environment is incremented. You can also append additional metadata to each version, like a git commit
or a deployment
tag.
Workers Service Bindings
Workers Service bindings are an API that facilitate Worker-to-Worker communication.
A Workers Service binding allows you to send HTTP requests to another Worker without those requests going over the Internet. The request immediately invokes the downstream Worker, reducing latency as compared to a request to a third-party service. You can invoke other Workers directly from your code; Workers Service bindings allow for much more composability on the Workers platform. In the example below, requests are validated by an authentication Workers Service.
export default {
async fetch(request, env) {
// Fetch AUTH service and pass request
const response = await env.AUTH.fetch(request);
// Return response from the AUTH service if the response status is not 200
// It would return 403 'x-custom-token does not match, request not allowed' response in such case
if (response.status !== 200) {
return response;
}
// Request allowed
const data = ''; // For example, read data from KV, Durable Objects, or Database
return new Response(data);
},
};
Workers Service bindings use the standard
Fetch API
. You can continue to use your existing utilities and libraries - a Workers Service binding will trigger a FetchEvent
. You can also change the environment of a Workers Service binding, so you can test a new version of a Service.
In the next example, 1% of requests are routed to a CANARY
deployment of a Worker. If a request to the CANARY
fails, it is sent to the production deployment for another chance.
export default {
canRetry(request) {
return request.method === 'GET' || request.method === 'HEAD';
},
async fetch(request, environment) {
if (Math.random() < 0.01) {
const response = await environment.CANARY.fetch(request.clone());
if (response.status < 500 || !canRetry(request)) {
return response;
}
}
return environment.PRODUCTION.fetch(request);
},
};
While the interface among Workers Services is HTTP, the networking is not. Unlike the typical microservice architecture, where services communicate over a network and can suffer from latency or interruption, Workers Service bindings are a zero-cost abstraction. When one Worker invokes another, there is no network delay and the request is executed immediately.
Workers Service bindings allow you to:
- Segment multiple use cases into separate Services that can be explicitly invoked from your code.
- Achieve better composability on the Workers platform using Service-oriented architecture.
- Create private microservices, to be conditionally invoked from other edge-facing Services.
Composing an example Worker
Authentication Workers Service
Following authentication Workers Service code responds with 200
in case x-custom-token
request matches SECRET_TOKEN
secret binding.
export default {
async fetch(request, env) {
// Read x-custom-token header and make sure it matches SECRET_TOKEN
if (request.headers.get('x-custom-token') === env.SECRET_TOKEN) {
return new Response('Request allowed', { status: 200 });
} else {
return new Response('x-custom-token does not match, request not allowed', { status: 403 });
}
},
};
This authentication Workers Service does not need to have a *.workers.dev
or other domain endpoint, nor does it need an HTTP Route: it is accessed through a Workers Service binding from the other Worker directly. The authentication Worker is, effectively, a private Worker Service.
Gateway Worker and Service bindings usage
In order to bind and call the authentication Workers Service above , the application Workers Service needs to set up a Workers Service binding. You can manage Workers Service bindings in Workers > select your Worker > Settings> Variables > Service Bindings > Edit variables.
Once added, the application Workers Service can access the Workers Service binding directly from the code, as in the example below.
export default {
async fetch(request, env) {
// Fetch AUTH service and pass request
const response = await env.AUTH.fetch(request);
// Return response from the AUTH service if the response status is not 200
// It would return 403 'x-custom-token does not match, request not allowed' response in such case
if (response.status !== 200) {
return response;
}
// Request allowed
const data = ''; // For example, read data from KV, Durable Objects, or Database
return new Response(data);
},
};
In this setup, only the Gateway Worker is exposed to the Internet and privately communicating with the authentication Workers Service using a Workers Service binding.