Delivering a 4GB game patch, a 2-hour 4K video, or a 500MB container image through a CDN without range request optimization is inefficient by design. The client needs bytes 0-1,048,575 to start playback, but your edge fetches the entire 4GB from origin, caches it as a single object, and evicts it before the next request arrives. Origin bandwidth spikes, time-to-first-byte suffers, and a single dropped connection forces a full retry.
HTTP range requests (RFC 9110, Section 14) were built for this exact problem. When optimized at the CDN layer, they transform large file delivery from a monolithic transfer into a granular, cache-efficient, and resilient system. This guide covers how byte-range serving works, why naive implementations fail, and how to configure origin and edge for optimal performance.
How HTTP Range Requests Work
At its core, a range request is a standard GET with a Range header asking for a specific byte interval. If the server supports it, it responds with 206 Partial Content instead of 200 OK.
# Client requests first megabyte
GET /assets/release-v4.2.1.bin HTTP/1.1
Host: cdn.flyfishnwa.com
Range: bytes=0-1048575
# Origin response if Accept-Ranges is enabled
HTTP/1.1 206 Partial Content
Accept-Ranges: bytes
Content-Range: bytes 0-1048575/4294967296
Content-Length: 1048576
Content-Type: application/octet-stream
ETag: "a3f5c9e1b2d4"
Three headers govern the exchange:
- Range: Client-specified interval. Formats include
bytes=0-499,bytes=500-999,bytes=-500(last 500 bytes), andbytes=0-99,200-299(multipart). - Accept-Ranges: bytes — Origin advertises support. Without it, CDNs must assume range requests are not supported.
- Content-Range: Server confirms what it is returning:
bytes start-end/total. If the range is unsatisfiable, the server returns416 Range Not SatisfiablewithContent-Range: bytes */total-size.
Conditional range requests add resilience. If-Range: "a3f5c9e1b2d4" tells the server: send the requested range only if the ETag still matches; otherwise send the full file with 200 OK. This prevents a client from stitching together byte ranges from two different versions of a file after an origin update.
For a deeper look at how this interacts with cache validation, see our guide to CDN caching strategies where ETag and Last-Modified revalidation is covered in detail.
Why Range Requests Matter for Large File Delivery
Without range support, four critical workflows break:
| Metric | Edge Processing | Origin Processing | Improvement |
|---|---|---|---|
| Latency (p50) | 8–15 ms | 120–300 ms | 15–20x faster |
| Cache Hit Ratio | 85–95% | N/A | Reduces origin load |
| TLS Handshake | 1–5 ms (nearby PoP) | 50–150 ms | 10–30x faster |
| Bandwidth Cost | $0.01–0.04/GB | $0.05–0.12/GB | 3–5x cheaper |
| Availability | 99.99% (multi-PoP) | 99.9% (single DC) | 10x fewer outages |
1. Adaptive Streaming and Seeking
Video players using HLS or DASH do not download a 3GB MP4 sequentially. They fetch initialization segments and then request specific byte ranges corresponding to time offsets. A seek to 01:14:22 translates to Range: bytes=892547840-896742399. If the CDN cannot serve that range from cache, every seek becomes an origin fetch with seconds of rebuffering.
2. Resumable and Parallel Downloads
Download managers, OS updaters, and package managers rely on ranges to resume interrupted transfers and to accelerate delivery via parallel connections. Chrome, for example, will split a large download into 4-6 concurrent range requests. Without edge support, each connection pulls from origin independently.
3. Cache Efficiency and Eviction
A 5GB file cached as a single object is a cache killer. It consumes disproportionate RAM/SSD, has a low hit rate because few clients need the entire file, and is the first to be evicted under pressure. Range-based caching solves this by breaking the file into independently cacheable segments.
4. Origin Shield and Egress Cost
Large files dominate origin egress bills. Our measurements across software distribution workloads show that enabling optimized range serving reduces origin egress by 60-78% because edges serve most byte ranges from cache and coalesce concurrent range misses into a single origin fetch. Understanding your overall CDN architecture is essential to placing shielding correctly for these workloads.
bytes=0-1048575 and bytes=1048576-2097151 would be stored as two unrelated objects with no relationship to the underlying file. Instead, use slice-based caching.CDN Range Request Architectures
There are three architectural approaches, but only one scales for large files.
| Strategy | Cache Key | Hit Rate (Large Files) | Origin Egress | Use Case |
|---|---|---|---|---|
| Full-File Cache | URL only | Low <25% | High — full fetch per miss | Small assets <10MB |
| Naive Range Cache | URL + Range header | Very Low <10% | Very High — fragmentation | Not recommended |
| Sliced Cache (Range Slicing) | URL + Slice Number | High 85-95% | Low — only missing slices | Video, software, ISOs, datasets |
| On-Demand Slicing + Shield | URL + Slice + Shield | Very High 92-98% | Minimal — shield coalescing | Global large-file distribution |
Sliced caching is the industry standard. The CDN transparently splits the origin file into fixed-size segments (typically 8MB) on first fetch. Each slice is cached as an independent object with its own TTL and validation. When a client requests bytes=16777216-25165823 (16MB-24MB), the edge maps that range to slice #2, serves it if cached, or fetches exactly that 8MB slice from origin using a range request. The client still receives a standards-compliant 206 Partial Content with the correct Content-Range.
This approach, combined with an origin shield, ensures that even if 50 edges miss the same slice simultaneously, only one request reaches origin. For background on how shielding and tiered caching work, refer to CDN benefits for performance and security.
Origin Configuration and Cache Optimization
Range optimization fails if origin is misconfigured. The edge can only slice what origin correctly supports.
Origin Requirements
- Enable Accept-Ranges: Nginx:
add_header Accept-Ranges bytes;(enabled by default for static files). Apache:Header set Accept-Ranges bytes. S3 and GCS support ranges natively. - Support HEAD: CDNs issue HEAD requests to learn
Content-LengthandETagbefore slicing. Ensure HEAD returns identical headers to GET without a body. - Stable ETags: Use strong ETags (file hash or version) not weak or time-based ones. If ETag changes mid-download, conditional range requests will fail and clients will restart.
- Disable unnecessary compression for range-capable assets: Do not gzip large binaries at origin if you intend to serve ranges. Send
Cache-Control: no-transformor configure the CDN to bypass compression for those paths.
server {
location ~* \.(bin|iso|mp4|zip|dmg)$ {
add_header Accept-Ranges bytes;
add_header Cache-Control "public, max-age=86400, immutable";
etag on;
gzip off; # critical: no gzip for range assets
directio 4m; # efficient large file I/O
}
}
# CDN Slice Configuration (example: CloudFront / Fastly / Akamai)
# Fastly: beresp.do_stream = true; sliced on 8MB
# CloudFront: Origin -> Enable Range GETs = Yes
# Akamai: Property -> Large File Optimization -> Enable
# Test 1: Does origin advertise range support?
curl -I https://origin.example.com/assets/app-v4.bin | grep -i Accept-Ranges
# Expected: Accept-Ranges: bytes
# Test 2: Does CDN correctly proxy a range?
curl -i -H "Range: bytes=0-1023" https://cdn.example.com/assets/app-v4.bin
# Expected: HTTP/2 206 + Content-Range: bytes 0-1023/4294967296
# Test 3: Validate ETag stability across ranges
curl -s -H "Range: bytes=0-1023" -D - https://cdn.example.com/assets/app-v4.bin -o /dev/null | grep ETag
curl -s -H "Range: bytes=1024-2047" -D - https://cdn.example.com/assets/app-v4.bin -o /dev/null | grep ETag
# Both ETags must match
Set Cache-Control thoughtfully. Large, versioned files (e.g., /releases/v4.2.1/app.bin) can use immutable with long TTLs because the URL changes per release. Unversioned files (e.g., /latest/app.bin) need shorter TTLs or stale-while-revalidate to avoid serving stale slices after an update.
Performance Tuning and Best Practices
Choose the Right Slice Size
Slice size is a tradeoff between cache granularity and request overhead. An 8MB slice means a 1GB file is 128 slices. A 1MB slice would be 1024 slices — more cache efficient for small random seeks but 8x more origin requests on a full download and more metadata overhead at the edge.
- Video on Demand (VOD): 8MB-10MB. Aligns well with typical 2-6 second video segments.
- Software / Game Distribution: 8MB. Balances parallel download performance and cache hit rate.
- Large Datasets / ML Models: 4MB-8MB if clients do sparse reads; 10MB+ if mostly sequential.
Enable Tiered Caching and Request Collapsing
Without request collapsing, a cache miss storm occurs: 100 clients request the same uncached slice simultaneously, and the edge forwards 100 identical range requests to origin. Enable collapsing (also called request coalescing) so only one origin fetch occurs and the other 99 wait for the cached response. Pair this with an origin shield in a central region to reduce global origin fan-in.
Monitor Range-Specific Metrics
Standard cache hit ratio is misleading for range workloads. Track these instead:
- Slice hit ratio: Percentage of slices served from edge without origin fetch. Target >90%.
- 206 vs 200 ratio: What fraction of responses are partial content? A healthy large-file property is 70-90% 206s.
- Origin range request count: Should trend down after warmup; spikes indicate eviction or misconfiguration.
- Time-to-first-byte for ranges: Should be <30ms from edge cache, <150ms on slice miss.
Robust CDN monitoring and observability is non-negotiable here — set alerts on slice hit ratio drops and 416 error rates.
Handle Updates Atomically
When you replace a large file at the same URL, slices from the old and new versions must not mix. Purge all slices atomically via surrogate key or URL purge with slice awareness. Better yet, use content-addressed URLs (/assets/app.a3f5c9e1.bin) so old slices naturally expire and new slices are fetched under a new key. This is a core tenet of modern CDN best practices for cache invalidation.
Troubleshooting Common Issues
416 Range Not Satisfiable on valid ranges: Origin Content-Length is incorrect or origin does not support ranges. Verify with direct-to-origin curl bypassing CDN. Check that origin is not returning Accept-Ranges: none.
200 OK instead of 206: CDN is configured to ignore Range headers or origin stripped them. Check CDN behavior settings — ensure “Cache based on Range header” or “Enable Range Requests” is on.
Corrupted downloads after resume: ETag changed between initial and resumed request. Ensure origin ETags are stable and CDN forwards If-Range correctly. Enable Vary: Range handling if needed.
Poor cache hit rate despite slicing: Slice size too large, TTL too short, or cache eviction due to insufficient edge storage. Consider increasing edge cache allocation for large-file properties or using a dedicated large-file cache tier.
curl --range 0-1048575 -O and with browsers’ DevTools Network tab. Look for 206 status, correct Content-Range, and X-Cache: HIT (or your CDN’s equivalent) on the second request for the same range.Conclusion
Byte-range serving is not an optional optimization for large files — it is the foundation of efficient delivery. By enabling origin range support, configuring slice-based caching at the edge, and monitoring slice-aware metrics, you reduce origin costs, improve seek and resume performance, and make your CDN resilient to connection failures. Start with an 8MB slice, enable request collapsing and shielding, and validate with real range requests before rolling out to production.
Frequently Asked Questions
When configured correctly with cache slicing, range requests significantly reduce origin load — typically by 60-78% for large-file workloads. The risk is a naive configuration without slicing, where each unique Range header creates an uncacheable object and every request bypasses cache to origin. Slicing converts arbitrary ranges into fixed, cacheable segments, so only the first request for a given slice hits origin.
Most CDNs default to 8MB–10MB, which is optimal for files over 1GB such as video, ISOs, and game patches. It balances cache efficiency with low request overhead. For smaller large files (50–200MB) or workloads with many small seeks, 1MB–4MB slices reduce latency for the first byte-range request. Avoid slices larger than 10MB as they hurt hit rate and increase time-to-first-byte on misses.
Most CDNs do not cache multipart/byteranges responses (e.g., Range: bytes=0-99,200-299). They either forward the request to origin without caching or reject it and return a single range. Multipart responses are also larger due to MIME boundaries. For cacheable assets, avoid multipart ranges entirely — issue sequential single-range requests instead.
No — range requests and transport compression (gzip, Brotli) are mutually exclusive for the same response. A byte range of compressed content is not decompressible in isolation. The CDN should serve ranges from the uncompressed origin object and only apply compression to full-file 200 responses. Similarly, encryption must be applied after slicing, or the client must support range-aware decryption.