Axios Memory Allocation in Large File Uploads

This article explores how the Axios HTTP client handles memory allocation during large multipart file uploads across both Node.js and browser environments. It examines the underlying mechanisms used to avoid high RAM usage—such as Node.js streams and browser Blob objects—while highlighting common configuration pitfalls that cause memory spikes and practical solutions to maintain low memory footprints.

Node.js vs. Browser Runtime Architecture

Axios acts as an isomorphic wrapper, meaning its memory management relies entirely on the host environment: Node.js or the browser.

1. Node.js Environment

In Node.js, Axios uses the native http and https modules. Memory management during a multipart upload depends directly on whether data is passed as a complete Buffer or as a ReadableStream.

  • Buffer-Based Uploads (High Memory): If a file is read entirely into memory using fs.readFileSync() before being appended to a FormData instance, the entire file size is allocated directly in the Node.js V8 heap. This can easily trigger an Out of Memory (OOM) crash for files larger than the available heap limit.
  • Stream-Based Uploads (Low Memory): By utilizing fs.createReadStream(), the file is read in small, sequential chunks (typically 64 KB by default). Axios pipes this stream into the HTTP request body. Only a tiny fraction of the file resides in the V8 heap at any given moment.
const fs = require('fs');
const axios = require('axios');
const FormData = require('form-data');

const form = new FormData();
form.append('file', fs.createReadStream('/path/to/large-file.zip'));

await axios.post('https://example.com/upload', form, {
  headers: form.getHeaders(),
  maxBodyLength: Infinity,
  maxContentLength: Infinity,
});

Stream Backpressure

Axios and the underlying Node.js stream implementation rely on backpressure handling. If the network socket is slower than the disk read rate, Node.js pauses reading from disk until the internal buffer drains, preventing unbounded memory growth.

2. Browser Environment

In browsers, Axios uses the native XMLHttpRequest (XHR) API.

  • File and Blob References: Browsers do not load an entire file into the JavaScript heap when selecting it via <input type="file">. Instead, the File object is merely a pointer to the file on the underlying operating system's filesystem.
  • Native Chunking: When a File or Blob is appended to a native FormData object and passed to Axios, the browser’s internal network stack reads and streams the file directly from disk to the network interface in native memory, bypassing the JavaScript engine's garbage collection and heap.
const formData = new FormData();
formData.append('file', fileInputElement.files[0]);

await axios.post('/upload', formData, {
  headers: { 'Content-Type': 'multipart/form-data' }
});

Critical Axios Settings for Large Uploads

By default, Axios includes safety caps to prevent runaway memory usage from unexpected payload sizes. When handling large files, these settings must be adjusted:

  1. maxBodyLength: Defines the maximum allowed size of the HTTP request body in bytes (default is 10 MB in Node.js). Setting this to Infinity allows large streams without throwing an error before transmission begins.
  2. maxContentLength: Defines the maximum allowed size of the HTTP response content. This should also be set to Infinity if the server returns large payloads.

Key Takeaways for Preventing Memory Leaks

  • Never convert large files to Base64 or full in-memory strings, as this increases payload size by ~33% and places the entire payload into the active JavaScript heap.
  • Always pass streams in Node.js instead of read buffers to maintain a constant, minimal memory footprint regardless of file size.
  • Let the browser handle native File objects rather than reading them via FileReader.readAsArrayBuffer() before upload.