Optimization guide · uploads

How do you optimize large uploads in Node.js?

Short answer

Do not solve a large upload by raising the maximum body size. Keep prefetch disabled, create ctx.bodyStream() before the first await, and send it to a downstream pipeline. Cap one stream with maxStreamBodySize, cap concurrent uploads, and budget the storage destination. swm-uws 0.7.3 stops socket reads on pause(), so a slow consumer creates backpressure instead of retaining the whole body in memory.

Readable
body stream
413
size exceeded
pause/resume
flow control

Scope

This page fixes the @swarmmachina/swm-core 5.1.2 and @swarmmachina/swm-uws 0.7.3 contracts for Node.js 22/24. It does not measure the throughput of a particular disk, object store, or network, and it does not promise a process-wide memory limit.

Streaming-upload contract

LayerExplicit boundaryPre-release check
ReaderCreate ctx.bodyStream() synchronously before the first await and do not use another body reader or prefetch for that request.Test an asynchronous before hook, reader conflict, and an early authorization refusal.
Sizehttp.maxStreamBodySize is the server ceiling; route and per-call maxSize can only narrow it.Check Content-Length above the limit and a chunked upload that crosses it while reading.
MemoryStreaming is not charged to maxBodyBudget, but downstream queues, retained chunks, and concurrent uploads still consume memory.Record RSS, queue depth, and active uploads in a separate load run.
BackpressureWhen a consumer is not ready, native pause stops further socket reads; chunks already in the parser buffer can still reach a callback.Slow the destination write, observe pause/resume, and verify that the process does not buffer the whole file.
CancellationWhen a handler stops reading the body, call stream.destroy() and finish the response under your own policy.Cover an authorization refusal, client FIN, and connection reuse after drain.
AdmissionOne file limit does not cap the total of simultaneous files: define a separate concurrency limit and storage budget.Start more concurrent uploads than the policy permits and prove that refusal is controlled.

Choose from the upload profile

  1. 01

    A small JSON or form payload

    Keep a bounded body reader

    body(), json(), or prefetch is simpler when materialization is inside a known limit and the application needs the complete value.

  2. 02

    A file goes to disk or object storage

    Use ctx.bodyStream()

    The pipeline receives chunks as they arrive and does not need to hold the complete file in JavaScript memory.

  3. 03

    The downstream is temporarily slower than the network

    Use pause/resume, but measure it

    Backpressure bounds socket reads, but it does not provide admission control or bound memory in every other part of the process.

What this does not promise

  • A stream does not make memory use infinitesimal: the parser buffer, consumer-held chunks, and downstream queues remain budget items.
  • maxStreamBodySize limits one request, not the total of concurrent uploads or the object-storage budget.
  • Do not mix a streaming reader with body(), buffer(), text(), json(), or prefetch in one request.
  • This page describes a contract, not a universal benchmark. Verify performance with your file sizes, disk, network, and concurrency.

Primary sources

Claims about the reader, limits, and pause/resume are pinned to the published package versions.