Why Workers Can't Just Upgrade the Runtime
Cloudflare Workers runs customer code in a distributed serverless environment. The platform's central promise is that developers manage only their own code, never the underlying runtime — Cloudflare updates the runtime for everyone, at least weekly, and often more frequently.
That model places a hard constraint on the Workers team:
A change to the Workers Runtime must never break an application that is live in production.
This is a sharper requirement than traditional infrastructure. A developer running Node.js on their own VM chooses when to move from Node 14 to Node 16, tests against a staging environment, or stays on a long-term support release. If a breaking change lands in a new Node major, that developer opted in by upgrading. In a serverless world, the developer has no control over the runtime upgrade timeline, so breaking changes are effectively unannounced deployments — the developer might be asleep or on vacation when their app stops working.
In practice, this policy collides with reality: sometimes fetch() and other runtime APIs simply have bugs that need fixing, but those fixes inevitably break someone's deployed Worker.
When a Bug Is a Feature
One concrete example: the original implementation of fetch() silently coerced non-HTTP URLs into HTTP. Calling fetch("ftp://example.com") would return the same result as fetching the HTTP equivalent. The intended behavior is to throw an exception. But a significant number of live Workers were built on the buggy coercion, possibly relying on sites that served both protocols, or treating a 404 as a less harmful failure than an exception.
Fixing the bug outright would break those deployments. That's not a scenario the platform can simply push back on the developer. The developer tested their code against the platform and it worked; the mismatch is the platform's fault, not the application's. Asking that developer to drop ongoing work to patch code that has run fine for years is the wrong answer for a serverless product.
Why Version Pinning Fails
Running multiple runtime versions per application is also not viable. To deliver edge computing at scale, each runtime instance must host a very large number of Workers. Per-application runtime instances would raise costs dramatically and reduce the geographic spread of deployments.
Beyond cost, letting developers pin infinite old versions undermines the promise that they won't need to manage a stack. That path leads to security-patch alerts, version-specific documentation, and an obligation to explain long-term support timelines. And it still doesn't solve the real problem: the runtime binary could support multiple behaviors, but there would need to be a mechanism to select the right one per Worker.
Compatibility Dates: Opt-In Breaking Changes
The result is a per-Worker "compatibility date," always in the past, supplied in the project's metadata — for Wrangler projects, in wrangler.toml — and sent to the Cloudflare API with each code deploy. The date defaults to the Worker's creation date.
This design lets Cloudflare ship a breaking change while implementing both old and new behavior inside the same runtime. Each breaking change is assigned a date in the future that flips the default; Workers whose compatibility date is at or later than that date get the new behavior, while older Workers keep the existing semantics.
The public compatibility dates documentation lists only breaking changes — a developer updating their compatibility date can review the page to identify what might require testing. Everything else, including new features and non-breaking fixes, ships unconditionally without requiring a compatibility date bump.
Developers can ignore the mechanism entirely; old compatibility dates are intended to be supported forever. But anyone actively deploying code should advance the compatibility date alongside those updates.
Cloudflare credits Stripe's API versioning, the Linux kernel's stable system call interface, and the Web Platform's browser-driven backward compatibility as inspiration for the approach.



