HTTP range requests let a client ask for only part of a representation instead of downloading the entire body. They are useful for resumable downloads, media seeking, large files, and clients that need a known byte segment.
The core mechanism is simple, but correct servers need to distinguish valid ranges, unsatisfiable ranges, validators, and ordinary full responses.
A client requests a byte range
A request can include:
Range: bytes=1000-1999If the server supports the request and the selected representation is 8,000 bytes long, it can respond:
HTTP/1.1 206 Partial Content
Content-Range: bytes 1000-1999/8000
Content-Length: 1000The body contains exactly the selected bytes.
A 206 Partial Content response is different from a normal 200 OK response. Clients use the status and Content-Range metadata to understand how the body fits into the complete representation.
Advertise support deliberately
Servers commonly indicate byte-range support with:
Accept-Ranges: bytesThis is useful for clients planning resumable or seekable behavior.
Do not advertise range support if an upstream storage layer, transformation pipeline, or dynamic representation cannot reliably serve stable byte offsets.
Range handling is easiest for static or otherwise byte-stable representations where the total length is known.
Understand the common range forms
Byte ranges can express several shapes.
A bounded range:
Range: bytes=1000-1999An open-ended range:
Range: bytes=1000-A suffix range requesting the final bytes:
Range: bytes=-500Servers must normalize these forms against the current representation length before reading data.
For a resource of length 8,000, bytes=1000- means bytes 1,000 through 7,999. A suffix request of bytes=-500 selects the final 500 bytes.
Reject unsatisfiable ranges correctly
If no requested byte range overlaps the current representation, respond with 416 Range Not Satisfiable and communicate the current length:
HTTP/1.1 416 Range Not Satisfiable
Content-Range: bytes */8000Do not silently turn every malformed or impossible range into an arbitrary slice. Range parsing is part of the protocol surface and should be validated carefully.
Also protect integer arithmetic when converting inclusive byte positions into offsets and lengths. User-controlled range values should not be allowed to overflow calculations or trigger huge allocations.
Avoid loading the whole object to serve a small range
A range endpoint provides little performance value if it reads an entire multi-gigabyte object into memory and then slices it.
Prefer storage APIs that support seeking or bounded reads:
requested start/end
-> validate against length
-> seek to start
-> stream exactly N bytesFor object storage, use the provider’s native range-read capability when available. For local files, seekable file handles can serve the selected region without buffering the whole file.
The HTTP optimization should continue through the storage path.
Keep byte offsets tied to one representation
Byte positions are meaningful only for a specific representation.
If a server dynamically compresses a response, bytes 1000-1999 of the compressed representation are not the same as bytes 1000-1999 of the uncompressed file.
Similarly, content negotiation can select different representations for the same URL.
Range handling therefore needs to align with caching and representation selection. A server should know which concrete bytes its validators and lengths describe.
Use validators when resuming downloads
Suppose a client downloaded the first half of a file yesterday and wants to resume today. If the file changed, appending bytes from the new representation to bytes from the old one can corrupt the result.
If-Range lets the client condition a range request on a validator. Conceptually:
Range: bytes=4000000-
If-Range: "file-version-abc"If the validator still matches, the server can return the requested range. If it does not, the server sends the full current representation instead of combining incompatible versions.
This is an important detail for robust resumable downloads.
Multiple ranges add complexity
HTTP can represent multiple requested ranges, such as:
Range: bytes=0-99,200-299A server that supports multiple ranges may respond with a multipart body containing each selected segment.
That complexity is unnecessary for many applications. If your product only needs single-range downloads or media seeking, explicitly support the subset you can implement and test correctly according to the protocol behavior expected by your clients and infrastructure.
Be particularly cautious with requests containing many tiny ranges because they can amplify parsing and response overhead.
Proxies and CDNs need compatible behavior
A range-capable origin does not guarantee identical behavior through every intermediary.
Check how your CDN or reverse proxy handles:
- caching
206responses; - forwarding
RangeandIf-Range; - compressed variants;
- coalescing range requests;
- origin requests for uncached segments.
Test the deployed path, not only the application server.
Security and resource limits still apply
Range requests are user-controlled input. Defensive implementations should limit pathological behavior.
Useful controls include:
- a maximum number of ranges if multiple ranges are supported;
- validated numeric parsing;
- bounded response sizes where product requirements permit;
- normal authentication and authorization checks before data access;
- request deadlines and cancellation;
- rate limits for expensive storage backends.
A range header does not bypass access control. Authorization applies to the representation before any byte subset is served.
Common pitfalls
Returning 200 for a body that contains only a slice
A partial response needs the correct 206 status and Content-Range metadata so clients can interpret it safely.
Ignoring representation changes during resume
Use validators and If-Range when clients combine previously downloaded bytes with a new request.
Reading the full object before slicing
Push range selection down to seekable files or range-aware storage APIs.
Mixing compressed and uncompressed offsets
Byte ranges apply to the selected representation. Keep length, validators, and encoding consistent.
Trusting arbitrary range arithmetic
Parse defensively and reject invalid or unsatisfiable requests without dangerous allocations.
Use ranges when partial bytes are a real product feature
Range requests are valuable when users actually resume, seek, or retrieve segments of large representations. They are not a universal performance switch for every endpoint.
When they fit the use case, implement them end to end: validate the requested range, stream only the needed bytes, return correct status and headers, bind resumed requests to representation validators, and test behavior through the same proxies and storage systems used in production.