Fahim Khan Profile
Fahim Khan
Software Consultant

Quick Contact

✉
fahimkhan20148@gmail.com
📱
+971 507 286 133
Back to Blogs
Implementing Resumable Downloads in React and Node.js

Implementing Resumable Downloads in React and Node.js

November 23, 2024
ReactNodeJSExpressNestJSresumabledownloadsHTTPRangeIndexedDBTypeScriptwebdevelopmentfrontendbackendchunkedfilebinaryprogressiveAPI

Github repo

Resumable downloads solve a persistent problem in web applications: large files (such as binaries or archives) are often interrupted due to connection issues, device sleep, or user navigation. Without resumability, any failure forces the user to restart their download from scratch, which is inefficient for both end users and servers.

Core Solution: HTTP Range Requests + Chunked Download State

Modern HTTP servers and browsers support the Range header, which allows partial retrieval of resources. When paired with persistent client storage (using IndexedDB, for example), this enables fully resumable downloads in the browser.

Backend Implementation

Express and NestJS servers handle HTTP Range headers, serving only the requested byte range of a file, with status 206 to indicate partial content.

express

Frontend Implementation

A React hook stores partial downloads in IndexedDB, tracks byte offsets, and resumes at the correct point after pause, reload, or disconnect. Once all chunks are downloaded, it assembles the file for the user:

downloadChunk

Key Technical Points

  • Download state survives reload and can be paused/resumed at any point.
  • Each chunk is managed as a binary ArrayBuffer, never loading the full file in memory until final assembly.
  • AbortController cleanly pauses any in-flight XHR/fetch.

Alternative Use Case: Chunked Download for Tabular Data

Beyond binary files, this architecture also supports resumable downloads for very large tabular datasets (e.g., tens of thousands of CSV rows).

How it works for tabular data:

Instead of requesting byte ranges, the client requests row ranges:

GET /download-csv?startRow=10000&endRow=11999

The server streams the requested rows, with each chunk immediately valid and usable (often including the header for parsing).

The file "size" is now governed by the total number of rows, and the client tracks row index, not byte position.

Persistence, pause, and resume work the same way; each downloaded chunk can be parsed and used for analytics or preview as soon as it arrives, with no need to wait for the entire dataset.

Example use cases for this variation:

  • Data analytics dashboards exporting millions of rows for local processing
  • BI tools and reporting apps requiring partial preview and progressive download
  • Database extracts where pagination by row is more meaningful than bytes

Technical Summary

The general resumable download pattern—partial retrieval, persistent storage of state, pause/resume functionality—is broadly applicable beyond static files. For tabular or record-based data, switching from byte-based to row-based chunking improves usability and efficiency, letting users access part of their data immediately while maintaining robust resumability.

This architecture improves reliability, user experience, and resource efficiency for large downloads—whether files or tabular data—across a wide range of web applications.

Demo

Check out the GitHub repository for a live demo and complete implementation details.

Open on YouTube