Skip to content
audiotale.net
Sign in
NewsNews

Cloudflare Origin Range Requests: all plans, R2 p99 TTFB halved

Cloudflare has rebuilt range-request caching: a Cache Rule switch on every plan, no range size to tune, and what to check on your origin first.

audiotale.net team

· 9 min read

Written by AI from the sources linked below. How we use AI

The entrance area of a Cloudflare office
Photo: HaeB, CC BY-SA 4.0, via Wikimedia Commons
On this page
  1. Key points
  2. What to do
  3. What happened
  4. Background
  5. The numbers
  6. How it works
  7. What it means
  8. What we don't know yet
  9. What to watch next
  10. Sources

Cloudflare has replaced the way its cache handles HTTP range requests, the "give me bytes 100 to 199 of this file" requests behind video seeking, resumable downloads and partial reads of large files. The new setting, Origin Range Requests, is self-service on every plan, switched on with a Cache Rule, and has no range size to tune. Cloudflare says it roughly halved p99 time to first byte for R2 on both cache hits and misses. If you serve large files through Cloudflare, this is one of the few CDN changes that can be tried in an afternoon.

Key points

  • Origin Range Requests is available on all Cloudflare plans: create a Cache Rule that matches your large-file traffic and set Origin Range Requests to On (API: origin_range_requests: { "mode": "on" }).
  • It replaces the old per-zone setting in which you chose a fixed range size; the cache now uses the fixed-size chunks its Pingora-based cache already stores on disk.
  • Cloudflare reports that across R2's storage regions p99 time to first byte fell by roughly half on cache hits and misses, and that a follow-up change cut tiered cache traffic for R2 and similar workloads by about 6% week over week.
  • Cloudflare's documentation says the origin may now see requests aligned to 1 MiB boundaries, and that it asks origins for unencoded bytes with Accept-Encoding: identity.
  • It does not make anything cacheable that wasn't, it is not supported with Cache Reserve, and it only helps if your origin honours byte ranges.

What to do

Who is affected: anyone who serves large files through Cloudflare's cache and whose clients read them in pieces: seekable MP4 video, large downloads that resume, package repositories, disk images and archives, AI model files such as GGUF, and clients that read small regions of big objects. Small files that are always fetched whole gain nothing.

How to turn it on:

  1. In the dashboard open Caching > Cache Rules, create a rule that matches only the hosts and file extensions where clients read in pieces (for example .mp4, .zip, .iso, .gguf), and set Origin Range Requests to On. Through the API the action parameter is origin_range_requests: { "mode": "on" }; check the Cache Rules reference for the surrounding payload.
  2. Confirm first that the origin supports byte ranges and that the objects are cacheable. Cloudflare says the feature does not make an uncacheable response cacheable.
  3. Test afterwards. Per the documentation, a valid single range should return 206 Partial Content, an out-of-bounds range 416 Range Not Satisfiable, and an If-Range that no longer matches the ETag or Last-Modified date should return the whole file as 200.
  4. Plan for the origin side: Cloudflare's docs say origin requests are aligned to 1 MiB boundaries, so your origin can receive larger ranges than the client asked for, or several single-range requests. Check logs, rate limits and request signing (signed URLs) against that.
  5. If you use Cache Reserve, note that the documentation says the two are not supported together.

If you did nothing before: you have nothing to fix. Cloudflare says it intends to make this the default for certain file types, changeable through Cache Rules, but gives no date.

What happened

Cloudflare published "Origin Range Requests: Serving large files without range-request tuning" on its blog on 23 October 2026 (the date in the page's metadata); a developer documentation page describes the behaviour in detail. The post describes a rebuilt path for range requests in the cache that replaces a feature customers had to configure by hand.

A range request is an ordinary HTTP GET with a Range header. A video player uses one to jump to minute 40 without downloading the first 39; a download manager uses one to resume; a client reading a model file may read only the bytes holding one tensor. A CDN has to decide how to cache such traffic. Cache the whole file and you pay for a full download from the origin before the first byte can be served. Cache only what was asked for and you may end up with thousands of overlapping fragments.

According to Cloudflare, the old design sat between those extremes. Range caching was configured per zone: the customer set a fixed range size and a list of file extensions, and each client request was mapped onto fixed-size ranges of the file. Configured sizes ran from tens of kilobytes to tens of gigabytes. The range size was part of the cache key, so changing it invalidated cache entries.

The new design drops the customer-chosen size. For a range request, the edge serves any cached bytes straight from disk, fetches only the missing bytes from the origin in chunk-aligned ranges, stores them in the normal cache chunks and returns just the bytes the client requested. A "coordinator" assembles the response from cached data, downloads already in flight and new origin fetches, and writes accurate Content-Range and Content-Length headers. A request can attach itself to an existing download that already covers its bytes, so a burst of requests for a popular file shares one origin fetch.

Background

Range requests are old: they date back to HTTP/1.1. What changed over the years is the scale of the files behind them. Video, game patches, container layers and, more recently, multi-gigabyte model weights are routinely read in parts.

Cloudflare's post lays out why the fixed-size scheme hurt. Small ranges meant many small origin requests, plus memory pressure from combining them in memory. Large ranges meant Cloudflare downloaded far more than the client asked for, sometimes after the client had gone. Concurrent requests that fell in the same range could block one another however far apart the bytes they wanted were. The older nginx-based cache, the post says, could not combine range caching with concurrent streaming: each range had to finish downloading before anyone could read it, and a popular file needed a separate origin fetch per range. The extra bytes were then multiplied across the origin, the cache tiers and the client.

R2, Cloudflare's own object storage, was the sharpest example. Its range size was 64 MiB, so a small read that crossed a range boundary could cost 128 MiB of transfer between data centres. The replacement builds on something the cache already did: Cloudflare's Pingora-based cache stores cached files on disk in fixed-size chunks, and the post uses that chunk as the unit for ranges. The post does not state the chunk size; the documentation says only that origin requests are aligned to 1 MiB boundaries.

The numbers

Cloudflare's own measurements, all for R2:

  • Across R2's storage regions, p99 time to first byte dropped by roughly half on both cache hits and cache misses.
  • A later change, letting one response combine bytes already on disk with bytes fetched from upstream, cut tiered cache traffic for R2 and similar workloads by about 6% week over week. The post describes this as petabytes less data moving between data centres each day.

These are Cloudflare's internal numbers; no independent benchmark has been published that we found, and the post does not give absolute latencies or the traffic mix. Treat "about half" as the company's figure for R2, not a promise for your origin.

An independent write-up by developer Umesh Malik makes the amplification concrete with his own model, not Cloudflare's measurements: reading 4 MiB at a random offset in an 8 GiB file with 64 MiB ranges averages about 68 MiB of origin bytes, roughly 17 times what was needed.

Origin bytes for one 4 MiB read under 64 MiB ranges (the write-up's model, and Cloudflare's boundary-crossing case)MiB
Origin bytes for one 4 MiB read under 64 MiB ranges (the write-up's model, and Cloudflare's boundary-crossing case) (MiB)
MiB
Requested by client4
Average origin bytes68
Worst case, crossing a boundary128

Source: Umesh Malik's model; Cloudflare blog (128 MiB boundary case)

How it works

The documentation spells out the client-facing behaviour, which is useful when you test:

  • No Range header: the full file as 200 OK.
  • One valid range (bytes=100-199, bytes=100-, bytes=-100): 206 Partial Content. Ends past the file size are shortened.
  • Unsatisfiable range (empty, inverted or out of bounds): 416 Range Not Satisfiable with Content-Range: bytes */<FILE_SIZE>.
  • Two to 300 valid, ascending, non-overlapping ranges: a multipart 206. More than 300, unparseable headers or non-bytes units are treated as a normal request and return 200.
  • If-None-Match and If-Modified-Since take precedence and can return 304. An If-Range that matches exactly keeps range behaviour; a mismatch returns the full file.
  • If Cloudflare must decompress an encoded response, it ignores Range and returns the full body.

On the origin side the contract is stricter than many servers assume. A 206 from the origin must be unencoded, carry a Content-Range that includes the full file size, have a numeric Content-Length equal to the returned interval, and omit Transfer-Encoding. An ETag, if present, must stay consistent. If the origin ignores Range and sends a full 200, Cloudflare can use it but must download the whole file. If it returns an encoded 206, Cloudflare does not cache it, and a response that has already started may reach the client with fewer bytes than promised. Only cacheable GET requests take this path; the maximum cacheable file size is checked against the full size from Content-Range, so small ranges cannot sneak past the limit.

What it means

For developers running large-file workloads behind Cloudflare, the practical gain is that range behaviour stops being a tuning exercise. Before, you chose a range size, hoped it fitted your access pattern and paid for the guess in latency or origin egress. Now there is one switch and a design that fetches in small aligned chunks while sharing in-flight downloads. The people who should look first are those paying for origin egress on large objects, and teams whose video or model-file users complain about slow seeks.

Who loses? Mostly nobody, but there are trade-offs. Because requests are aligned to 1 MiB, a tiny read can still pull a whole chunk; Malik's write-up warns that a broad rule can slow small files that were already fast, so scope the Cache Rule narrowly. Origins with request-signing or per-request rate limits may need adjustment, because they can now see more, and larger, range requests. And the feature does nothing for origins that cannot serve ranges.

What we don't know yet

  • The size of the cache chunk. The post does not say; the documentation gives 1 MiB for origin alignment.
  • Results outside R2: the published numbers are for R2 only.
  • When the default switches on for "certain file types", and which types. Cloudflare gives no timeline.
  • Whether the old per-zone range setting will be retired, and when. The post describes the new feature as replacing the old behaviour but we found no deprecation date.
  • Pricing effects: the post gives none; savings are framed as less origin and inter-data-centre transfer.

What to watch next

Watch Cloudflare's changelog and the Cache Rules documentation for the default-on change and for any retirement of the per-zone range setting. If you adopt the feature, compare origin egress and time to first byte before and after for a week, and test the 206, 416 and If-Range cases above against your own origin. Independent benchmarks outside R2 would be the most useful thing to appear.

For other Cloudflare-side engineering news this week, see how Cloudflare is bringing post-quantum cryptography to its geographically fenced key manager.

Sources

Written by

audiotale.net team

The official account of the people who run audiotale.net: announcements, conversation starters and the newsroom's drafts. Posts written with AI say so. Every other account here is a real person.