Skip to content

Version affinity

During a gradual deployment, each request has a random chance of routing to either version based on the specified percentages. This means the same user can be served content from a different version every time a request is made, which can cause version skew issues.

Version affinity solves this by deterministically assigning users to a version based on a stable identifier, so they consistently hit the same version across page loads and subrequests for the duration of the gradual deployment.

How it works

Set the Cloudflare-Workers-Version-Key header on the incoming request to your Worker:

Terminal window
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: foo'

For a given deployment, all requests with a version key set to foo will be handled by the same version of your Worker. The platform hashes the key and uses the result with the configured percentages to deterministically assign a version - you do not choose which version a key maps to.

As you progress a gradual deployment (for example, from 10% to 20% to 50%), users whose keys were already assigned to the new version will remain on it. Users on the old version will progressively move to the new version as the percentage increases, but will not flip back unless you roll back.

You can set the Cloudflare-Workers-Version-Key header both when making an external request from the Internet to your Worker, as well as when making a subrequest from one Worker to another Worker using a service binding.

Static assets

Version affinity is particularly important when your Worker serves static assets with content-hashed filenames (like index-a1b2c3d4.js), which is the default behavior of most modern build tools and frameworks.

During a gradual rollout, different versions of your application will have different asset filenames:

  • Version A's HTML references assets/index-a1b2c3d4.js
  • Version B's HTML references assets/index-m3n4o5p6.js

Without version affinity, a user can receive HTML from version A, but when their browser requests index-a1b2c3d4.js, that request may be routed to version B - which does not have that file - resulting in a 404 error and a broken page.

Configuring version affinity using any of the methods in Choose a version key prevents this entirely by ensuring all requests from the same user are routed to the same version.

Choose a version key

The right version key depends on what stable identifiers your application has available. You can set the header using a Transform Rule on your zone, which extracts values from the request without modifying your application code.

Authenticated applications

If your application has a user identifier in a cookie or header, this is the best option. Each user is deterministically assigned to a version and stays there across sessions, devices, and reloads.

Text in Expression Editor:

http.cookie contains "user_id"

Selected operation under Modify request header: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: http.request.cookies["user_id"][0]

Applications with sessions

If your application sets a session cookie, use the session identifier. This gives consistent routing for the duration of the session. If the session expires and a new one is created, the user may be assigned to a different version.

Text in Expression Editor:

http.cookie contains "session_id"

Selected operation under Modify request header: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: http.request.cookies["session_id"][0]

Anonymous or cookieless applications

If your application does not have any stable identifier in the request, you have two options:

Option 1: Use the client IP address. This is the simplest approach and requires no application changes. Users behind the same NAT or VPN will be grouped together, and mobile users who switch networks may change version, but for most applications this significantly reduces version flip-flopping compared to random per-request routing.

Text in Expression Editor:

true

Selected operation under Modify request header: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: ip.src

Option 2: Set a long-lived cookie from your Worker. On the first request (which will be randomly assigned), your Worker generates a stable identifier and sets it as a cookie. All subsequent requests use that cookie as the version key. This gives the best consistency for anonymous users, at the cost of a small amount of application code.

JavaScript
export default {
async fetch(request, env) {
const response = await handleRequest(request, env);
// Set a long-lived cookie to use as a version affinity key.
const COOKIE_NAME = "version-key"; // can be any name
const cookieHeader = request.headers.get("Cookie") ?? "";
const hasAffinityCookie = new RegExp(`(?:^|;\\s*)${COOKIE_NAME}=`).test(
cookieHeader,
);
if (!hasAffinityCookie) {
const id = crypto.randomUUID();
response.headers.append(
"Set-Cookie",
`${COOKIE_NAME}=${id}; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=31536000`,
);
}
return response;
},
};

Then create a Transform Rule to use this cookie as the version key:

Text in Expression Editor:

http.cookie contains "version-key"

Selected operation under Modify request header: Set dynamic

Header name: Cloudflare-Workers-Version-Key

Value: http.request.cookies["version-key"][0]

Testing

You can verify that version affinity is working by sending multiple requests with the same version key and confirming they are handled by the same version:

Terminal window
# Both requests should return responses from the same version
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: test-user-123'
curl -s https://example.com -H 'Cloudflare-Workers-Version-Key: test-user-123'

Use the version metadata binding to include the version ID in your Worker's response during testing.

During gradual rollouts, monitor your Worker's analytics for increased 404 response rates, especially for asset files (.js, .css, .png). Use Analytics Engine or Logpush to track these metrics and catch version skew issues early. If you notice problems, you can roll back to the previous version.