Caching partial requests without a range-size knob
An HTTP range request asks a server for part of a resource. The client issues a normal GET carrying a Range header:
GET /movie.mp4 HTTP/1.1
Host: example.com
Range: bytes=1048576-2097151
When the server honors the request, it replies with 206 Partial Content and identifies the returned bytes through Content-Range:
HTTP/1.1 206 Partial Content
Content-Range: bytes 1048576-2097151/524288000
Content-Length: 1048576
These requests are routine for large objects: a video player fetches bytes around a seek position, a download manager resumes an interrupted transfer, a package manager pulls part of an artifact, and a client can read the tail of a file without downloading what precedes it. Cloudflare does not alter the client's decision to request a range. Origin Range Requests changes how the edge satisfies that range.
Under the old implementation, a viewer seeking into the middle of a movie could cause Cloudflare to pull 128 MiB from the origin and shuttle it between data centers — occasionally after the viewer had already left. Range requests are the delivery mechanism for large files, and caching them naively wastes network bandwidth and disk operations at CDN scale.
The rebuilt implementation cut p99 time to first byte for R2, Cloudflare's object storage, by roughly half, and a subsequent improvement reduced tiered cache traffic for R2 and similar workloads by about 6%. It is now self-service on all plans as Origin Range Requests: there is no range size to tune and no support ticket required — a Cache Rule turns it on.
Why the old range-size setting was a trap
Range caching had existed for years as static zone configuration. The earlier design resembled the cache slicing described in an nginx blog post: every client request mapped to fixed-size ranges of the file, with the range size and file extensions configured per zone.
That size encoded an unavoidable tradeoff. Small ranges produced many small origin requests, and coalescing them in memory pressured Cloudflare; large ranges made the edge download far more than the client asked for. Because the range size was part of the cache key, changing it invalidated entries. Concurrent requests landing inside the same range could block one another regardless of how distant each client's requested span was. The nginx-based cache also could not combine range caching with concurrent streaming, which lets multiple clients read a file from cache while it is still being written — enabling both truncated responses, so each range had to finish downloading before anyone could read it, and popular files needed a separate origin fetch per range. Extra bytes multiplied across hops: origin to one data center, between cache tiers, then toward the client.
No single value suits a small seek, a sequential download, a large media file, and every origin and cache topology alike — which meant internal cache limitations leaked into customer configuration. The migration from nginx to the Pingora-based caching server opened the door to fixing the implementation instead of asking customers to tune it.
Reusing Pingora's fixed-size cache chunks
Pingora already stores every cached file on disk in fixed-size chunks so interrupted downloads can resume. The new design lets the chunk itself serve as the range size: for a range request, Cloudflare determines which requested bytes are already cached and serves them directly; missing bytes are fetched from the origin along boundaries aligned to the fixed-size chunks, stored in the same chunks ordinary caching uses, and only the bytes the client asked for are returned. A request for bytes 150-250, for example, may cause a fetch of the aligned chunk containing them, but the downstream response carries only 150-250.
Nor is all overhead gone: a request smaller than the chunk size can still force retrieval of the whole chunk, and non-aligned ranges mean additional work. What changes is that the extra work is bounded and predictable rather than governed by a customer-chosen range size with unpredictable effects on Cloudflare and origins.
One correct response from many sources
Parsing the Range header is trivial next to the hard part: assembling a single correct response when the requested bytes span cached data, an origin response, and downloads already in progress. The edge, at a high level:
- Looks up the asset headers and range-coverage metadata.
- Reads whatever part of the asset it can from disk or streaming in memory.
- Fetches missing coverage from the origin using aligned ranges.
- Writes the new bytes and records the completed range in metadata.
- Combines the pieces and sets
Content-RangeandContent-Lengthfor the client response.

The coordinator is not a single cache lookup: one request may use a cached prefix, an in-flight download, and a freshly fetched suffix. If an existing download covers the bytes another request needs, the second request attaches to it rather than starting its own origin fetch — sharing work during bursts on popular large files. The internal origin response may be larger than the downstream one, but status and headers describe only the requested range. The design sits on the existing cache data model: headers identify the asset version, the body lives in bounded chunks, and metadata records which ranges were written successfully.
Validation and HTTP conformance
Composed responses are valid only when every byte belongs to the same representation, so the coordinator verifies that each origin response matches the requested range, that the total asset size is stable, and that the entity tag stays consistent across subrequests. The If-Range header lets a client ask for a range only if the representation still matches a known validator; on a mismatch, Cloudflare returns the full representation instead of mixing bytes from different versions. Cloudflare also declines to compose ranges for a representation it is about to decompress, since a range over compressed bytes differs from the range selected in a decompressed response — in such cases the transformed full response is served rather than a range it cannot honor correctly.
The observable behavior remains standard HTTP:
- A satisfiable range receives
206 Partial Contentwith an accurateContent-Range. - An unsatisfiable range receives
416 Range Not Satisfiable. - A response that cannot safely be ranged is served as the complete representation.
Production results
Before general availability, existing users of the old feature were migrated to the new implementation starting with the heaviest workloads: many concurrent range requests against very large files on spiky traffic, with old configured range sizes spanning tens of kilobytes to tens of gigabytes. A large range size meant a request that would not fill a floppy could pull several DVDs' worth of data from the origin and move it across data centers, sometimes after the client had given up; a small range size turned one request into a long queue of tiny origin requests, each holding memory while it waited. Both patterns produced real operational incidents.
R2 was the largest internal user, with a configured range size of 64 MiB, so a small read crossing a range boundary could cost 128 MiB of inter-data-center transfer. After the migration:
- Faster responses. Across R2's storage regions, p99 time to first byte dropped by roughly half on both cache hits and misses.
- Fewer bytes on the network. The most recent change taught the coordinator to combine bytes already on disk with bytes fetched upstream in a single response; previously a request was served either wholly from cache or wholly from upstream. With it enabled for R2, tiered cache traffic for R2 and similar workloads fell about 6% week over week — petabytes less data moving between data centers daily.
Enabling it
With the range size no longer a customer setting, configuration is a Cache Rule that matches large-file traffic; the edge handles chunking and cache coordination. Typical targets include progressive and seekable video such as MP4, resumable large downloads, software distributions and package repositories, disk images and archives and other multi-gigabyte objects, AI training and inference workloads transferring large model files or fetching selected regions of model artifacts, and clients fetching metadata or a small region of a larger file. Cloudflare intends to make this the default way certain file types are served, modifiable by cache rules.
The feature does not change normal cache eligibility — enabling it will not make an otherwise uncacheable response cacheable — and the origin must support byte ranges for partial origin fetches to be useful. Turn it on in the dashboard under Caching > Cache Rules, or via the API with origin_range_requests: { "mode": "on" }. Customers choose the traffic; the edge handles the cache coordination and correctness requirements.



