---
title: Multipart uploads
description: Upload a large body in parallel parts instead of one request - the robust path past the single-request size limit and for streams of unknown length.
---

Multipart splits a body into parts and uploads them in parallel, then stitches them back together server-side. It's the robust path for objects beyond the single-request limit (5 GB on S3) and for `ReadableStream` bodies of unknown length: a single PUT must either buffer the whole body or know its length up front, while multipart streams part-by-part with bounded memory.

It's a per-call option on [`upload`](/api/upload) — the only method that writes a body, and so the only one to which it applies. Pass `multipart: true` for sensible defaults, or an object to tune `partSize` and `concurrency`:

```ts lineNumbers
// Defaults: 5 MiB parts, 4 in flight.
await files.upload("backups/db.tar", stream, { multipart: true });

// Or tune it:
await files.upload("backups/db.tar", stream, {
  multipart: { partSize: 16 * 1024 * 1024, concurrency: 8 },
});
```

In the [array form](/bulk), `multipart` is a per-item option — set it on each `{ key, body }` that needs it.

<AutoTypeTable
  path="../../packages/files-sdk/src/index.ts"
  name="MultipartOptions"
/>

## What each adapter does

The flag maps onto whatever chunking primitive the provider exposes, so the mechanics differ but the contract — a large body uploaded reliably — does not:

- **S3 and the S3-compatible adapters** (incl. R2 over HTTP) run multipart through the optional [`@aws-sdk/lib-storage`](https://www.npmjs.com/package/@aws-sdk/lib-storage) package, falling back to a single `PutObject` when the body fits in one part. Unknown-length streams use multipart **automatically**, even without the flag.
- **OneDrive** uploads above 250 MB (and any `multipart` request) go through a chunked upload session — large files that previously failed now just work.
- **GCS** and **Firebase Storage** switch to a resumable upload; `partSize` maps to the chunk size.
- **Azure Blob** already splits large bodies into parallel blocks; `multipart` only tunes the block size and concurrency.
- **Dropbox** streams `ReadableStream` bodies through its upload session chunk-by-chunk, so a large stream is never buffered whole; `partSize` (rounded to a 4 MiB multiple) tunes the chunk size.
- Other adapters already stream natively or only accept a fully-buffered body, so they ignore the option.

Adapters that chunk natively round `partSize` to their own valid granularity — OneDrive to a 320-KiB multiple, GCS and Firebase to 256 KiB — and S3 enforces a 5 MiB minimum for every part except the last.

## Sizing the parts

`partSize` and `concurrency` trade memory for throughput: up to `partSize × concurrency` bytes are buffered at once. The defaults (5 MiB × 4) keep that footprint small; raise them for fat pipes and large objects, lower them on memory-constrained workers. Because S3 caps an object at 10,000 parts, very large objects need a `partSize` big enough to fit under that ceiling.

## Progress and retries

When [`onProgress`](/api/onprogress) is set, the S3 family reports true byte-level progress across the whole multipart upload through the same `@aws-sdk/lib-storage` path. Multipart is still a single [`upload`](/api/upload) call as far as [retries](/retries), [timeouts](/timeouts), and [cancellation](/cancellations) are concerned — a failure retries the call, not an individual part, and an aborted [`signal`](/cancellations) fails it fast.

To pause and resume an upload — or resume one after a crash from a serializable token, retrying individual parts rather than the whole call — reach for a [resumable upload](/resumable) instead.
