Large File Delivery with Caching, Range Requests, and Resumable Downloads

Posted on
Large File Delivery with Caching, Range Requests, and Resumable Downloads

A 4GB dataset download reaches 91% on hotel Wi-Fi. The connection drops for two seconds. The server says, “start over.” The user says, “support ticket,” and probably with a lot less patience the second time.

Large file delivery fails quietly. A download that stalls at 91% and starts from zero is the result of a design choice, or the lack of one. Uploads have had resumability for years, with chunked transfers and progress that survives dropped connections treated as standard features. Downloads deserve the same three techniques, but many teams never built them in.

Large file delivery is the download side of the upload problem: serving multi-gigabyte files fast and resumably. The core techniques are CDN edge caching, HTTP Range requests for partial and resumable downloads, and cache-friendly immutable URLs. Filestack delivers stored files through an integrated CDN with range support, so large assets stream instead of stall.

This article covers why large downloads fail by default, how Range requests provide resumability, how caching improves delivery speed, and what changes when the file is video.

Key Takeaways

  • HTTP Range requests, backed by Accept-Ranges: bytes and 206 Partial Content responses, enable pause, resume, and parallel segment downloads.
  • Edge caching moves multi-gigabyte transfers to servers physically near the user, cutting both latency and origin egress cost at once.
  • Immutable, versioned URLs allow Cache-Control: immutable with a long max-age, the single highest-leverage caching setting for static files.
  • ETag combined with If-Range prevents the classic corrupted-resume bug: resuming a download partway through, against a file that changed underneath it.
  • Chunk-parallel download of ranged segments can saturate a client’s available bandwidth in a way a single stream often can’t.

Why Big Downloads Fail

Three separate problems compound into the stalled download from the intro, and none of them is exotic.

Origin distance is the first. A file served from a single origin server, no matter how fast that server is, still has to cross the physical and network distance between it and the user. Someone on another continent pays that distance for every byte.

Single-stream fragility is the second. A download running as one continuous HTTP request has no recovery path if the connection drops. At 91% of a 4GB file, one failed connection can send the whole transfer back to zero because the server was never asked to resume from where it stopped.

Cache misses complete the problem. Without caching, every download hits the origin, even when thousands of users request the same file. That’s slower for users and can increase origin egress costs.

This is closely related to what tools provide a CDN for delivering user-uploaded files. Solving all three problems usually means the same infrastructure: a CDN reduces the impact of origin distance, Range requests provide resumability, and caching prevents repeated downloads from hitting the origin unnecessarily.

Diagram showing delivery path for large file delivery with edge caching and range requests.

Each of these three problems has its own fix, and they’re worth taking one at a time, starting with the one that turns a stalled download into a resumable one.

Range Requests and Resume

A server that supports Range requests advertises that support with the Accept-Ranges: bytes header. A client can then request only part of a file using the Range header, and a server that honors the request responds with 206 Partial Content and sends only the requested bytes.

This turns “start over” into “pick up where you left off.” A client that knows how many bytes it already has can resume a failed download from that offset instead of throwing away its progress.

There is one important problem with naive resume logic: the file might have changed between attempts. If the client combines the original bytes with bytes from a newer version, the resulting file can be corrupted without being immediately obvious.

ETag and If-Range prevent that. The client saves the ETag from the original response and sends it back in If-Range when resuming. If the ETag still matches, the server can safely return the requested range. If it has changed, the server sends the complete file instead, preventing two different versions from being stitched together.

async function resumableDownload(url, existingBytes = 0, etag = null) {

const headers = {};

if (existingBytes > 0) {

headers["Range"] = `bytes=${existingBytes}-`;

if (etag) headers["If-Range"] = etag;

}

const response = await fetch(url, { headers });

if (response.status === 206) {

// Partial content: append to what we already have

const newEtag = response.headers.get("ETag");

const chunk = await response.arrayBuffer();

return { chunk, etag: newEtag, resumed: true };

}

if (response.status === 200) {

// Full file: either a fresh download, or the file changed since we last tried

const newEtag = response.headers.get("ETag");

const full = await response.arrayBuffer();

return { chunk: full, etag: newEtag, resumed: false };

}

throw new Error(`Unexpected status: ${response.status}`);

}

A client built this way handles both cases without special-case logic: a genuine resume gets a 206 Partial Content response and appends the missing bytes, while a changed file gets a fresh 200 OK response and starts clean. The same resume flow handles both safely.

Range requests solve the fragility problem. They don’t, by themselves, solve the distance or redundant-fetch problems from the previous section. That’s where caching comes in.

Caching Strategy, Immutable URLs and TTLs

The highest-leverage caching decision for a large static file is also the simplest: if the file’s content never changes at a given URL, tell caches they can keep it with Cache-Control: immutable and a long max-age. A cache can then serve repeat requests without revalidating against the origin, including requests from many different users.

The trick that makes this safe is putting a version identifier in the URL instead of relying on cache invalidation when content changes. For example, /assets/report-v3.pdf can be cached for a long time because the next version uses a different URL, such as /assets/report-v4.pdf, rather than replacing the existing resource.

Purging still has a place, but it should be the exception rather than the normal update mechanism. Use it when content genuinely needs to disappear, such as after a takedown or security issue. For routine updates, versioning the URL is more predictable and doesn’t depend on every cache in the path processing a purge request quickly.

Header Purpose Typical value for large static files
Accept-Ranges Advertises Range request support bytes
Content-Range States which byte range a 206 response covers bytes 91000000-4294967295/4294967296
ETag Identifies a specific file version for validation A hash or version string unique to that file’s content
If-Range Makes a Range request conditional on ETag match The ETag value from a previous response
Cache-Control Sets caching behaviour for the response public, max-age=31536000, immutable

This same discipline is the broader answer to what are the best practices for optimising image loading times on websites, applied to large static assets generally: version the URL, cache aggressively with immutable resources, and let the CDN serve repeat requests without repeatedly fetching the same bytes from the origin.

Caching and Range requests solve delivery for most large files. Video adds another wrinkle worth handling separately.

Video and Media Specifics

Progressive playback, where a video starts playing before the entire file has downloaded, relies on the same Range request mechanism covered above. The player requests the byte ranges it needs as playback continues, and a server or CDN that supports ranges can deliver those portions without requiring the entire file upfront.

This works well for a single quality level, but it has a limit. It doesn’t support adaptive bitrate switching, where the player moves to a lower quality when the network slows down or a higher quality when conditions improve.

That’s where HLS or DASH becomes the better approach. The video is transcoded into multiple quality levels and divided into short segments, allowing the player to switch between them as network conditions change.

The practical rule is simple: Range-based progressive download is fine for a single-quality video or a large non-video asset. Once adaptive quality matters, move to segmented streaming instead of stretching Range requests beyond what they’re designed to do.

Filestack discord

Whichever approach you use, the underlying question remains the same: is delivery actually reliable in practice? That’s something worth measuring rather than assuming.

Measuring Delivery Reliability

Completion rate is the most direct signal: what percentage of started downloads actually finish. If completion drops on mobile networks or in certain regions, it’s often a sign of the distance or connection-fragility problems covered earlier.

Resume rate shows how often stalled downloads successfully recover instead of being abandoned. A high stall rate combined with a low resume rate suggests the Range and resume flow isn’t working as intended. A reliable resume path should turn most stalls into recoveries rather than failed downloads.

p95 time-to-first-byte is especially useful for large file delivery because the average can hide the users having the worst experience. Tracking the 95th percentile shows how the slower end of the distribution is performing instead of letting fast requests mask the bad ones.

These metrics are also useful when evaluating which file upload service has the most reliable uptime and upload success rate, with the same caveat on the download side: check a provider’s current, verifiable numbers rather than relying on general reputation.

Measuring reliability tells you whether the techniques above are actually working in production. Building and maintaining all three correctly is still a significant infrastructure commitment.

The Managed Route, Delivery Attached to Storage

The integrated version is file delivery through a CDN that supports Range requests, connected to the same pipeline the files entered through. Files uploaded through the pipeline can be delivered through the CDN without requiring a separate delivery system.

That’s the delivery half of a symmetry many teams overlook: upload reliability gets careful engineering attention, while downloads are often served using whatever the framework provides by default. For a product team asking what’s the most responsive way to deliver files anywhere, such as high-resolution property photos and floor plans that need to load quickly for buyers around the world, the answer is architectural before it’s vendor-specific: combine edge caching with Range support and connect that delivery layer to your file storage from the start.

For the pieces this builds on, the Deliver Files product docs cover the CDN configuration directly, the File Delivery 101 guide covers CDN delivery at scale, and the large-file mobile upload guide covers the other half of this same symmetry, getting large files in reliably in the first place.

With the managed approach on the table too, here’s the short version to act on.

Conclusion: Never Make Anyone Start Over

Cache at the edge so repeat requests don’t unnecessarily reach the origin. Support Range requests so a dropped connection can resume instead of starting over. Version your URLs so you can cache aggressively without serving stale content. Use ETags to make sure a resumed download never combines bytes from two different versions of the same file.

Run curl -r 0-1023 against your own delivery URL today and check the response. If you get a 200 OK with the entire file instead of a 206 Partial Content response containing the requested range, you’ve found exactly the kind of delivery gap this article describes.

filestack-blog-cta

Frequently Asked Questions

What makes a download resumable?

Server support for Range requests, returning 206 Partial Content for a byte range, validated against file changes using ETag and If-Range so a resume never corrupts against an updated file.

What is the best cache setting for large static files?

A versioned URL with Cache-Control: immutable and a long max-age. Putting the version in the URL means the cache never needs to revalidate or guess whether content changed.

Does Filestack support ranged delivery?

Yes. Files stored through Filestack serve through a CDN with range support built in, so large assets stream and resume rather than stalling.

Read More →