---
cuppy_hub: aws
cuppy_path: guides/s3/upload-large-objects.md
cuppy_section: docs
cuppy_doc: Z4SQ-ZA0V
cuppy_doc_uuid: 1afa0de7-8c9b-4ce7-9956-33c1976600ce
cuppy_permalink: https://cuppy.io/aws/d/Z4SQ-ZA0V
cuppy_version: 4
cuppy_updated: 2026-10-23T16:16:52.575Z
cuppy_canonical: https://cuppy.io/aws/docs/guides/s3/upload-large-objects
cuppy_mcp: https://cuppy.io/mcp
cuppy_body_sha256: 6bdd90b1acd8d5c464381ca9da83050e1f5a3888ec585dd18c10293d5642c558
# cuppy_body_sha256 is over the document body ALONE, excluding both generated blocks.
---


# Upload large objects with multipart upload

**Use multipart upload from about 100 MB, and let the SDK's helper do it.** It splits the file into parts uploaded in parallel and retried individually, then S3 assembles the object. Objects can now be up to 48.8 TiB (announced as 50 TB in December 2025, up from 5 TB).

## Limits you must design around

| Item | Limit |
|---|---|
| Parts per upload | 10,000 |
| Part size | 5 MiB – 5 GiB (the last part may be smaller) |
| Largest object | 48.8 TiB |

At 10,000 parts, the part size sets the largest file you can upload: 8 MiB parts reach about 78 GiB; for a 1 TiB file parts must be at least about 105 MiB. Pick the part size from the expected maximum file size, not from a default.

## TypeScript: the Upload helper

```ts
import { S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { createReadStream } from "node:fs";

const upload = new Upload({
  client: new S3Client({ region: "<bucket region>" }),
  params: { Bucket: "<bucket>", Key: "<key>", Body: createReadStream("./big.bin") },
  partSize: 64 * 1024 * 1024, // bytes; size for your largest file (see above)
  queueSize: 4,               // parts in flight
});
upload.on("httpUploadProgress", (p) => console.log(p.loaded, p.total));
await upload.done();
```

`@aws-sdk/lib-storage` works in Node.js and browsers and replaces SDK v2's `upload()`. AWS recommends the latest CRT-based transfer tooling for very large objects. `partSize` and `queueSize` were checked against the package's TypeScript types.

## CLI

`aws s3 cp ./big.bin s3://<bucket>/<key>` switches to multipart automatically for large files (UNVERIFIED threshold). For explicit control: `aws s3api create-multipart-upload`, `upload-part` per part, `complete-multipart-upload` with the ordered part list, or `abort-multipart-upload`.

## Permissions

`s3:PutObject` on the object ARN covers the multipart calls. On an **SSE-KMS** bucket, multipart needs **`kms:Decrypt` as well as `kms:GenerateDataKey`**: a role that can upload small files but fails on large ones is usually missing `kms:Decrypt`.

## What it changes and costs

Uploaded parts are kept until the upload is completed or aborted, and are billed as storage until the upload is completed or aborted (the `CreateMultipartUpload` API documentation says so). An upload that is never completed leaves parts behind that do not appear as objects; abort failed uploads in code, and add a lifecycle rule that aborts incomplete multipart uploads after a few days (UNVERIFIED rule name in the collected sources: `AbortIncompleteMultipartUpload`). Completing the upload creates or replaces the object and emits `s3:ObjectCreated:CompleteMultipartUpload`, **not** `s3:ObjectCreated:Put`: an event notification that listens only for `Put` never fires for large uploads (`patterns/s3-to-lambda.md`).

## Errors

| Code | Cause → fix |
|---|---|
| `EntityTooLarge` | Single-request upload above the limit: switch to multipart |
| `EntityTooSmall` | A non-final part under 5 MiB: raise `partSize` |
| `InvalidPart` | A listed part is missing or its ETag does not match: re-upload that part |
| `InvalidPartOrder` | Complete request lists parts out of order: sort by part number |
| `NoSuchUpload` | The upload ID was already completed or aborted, or is wrong |
| `InvalidRequest` | Includes `CopyObject` on an object over 5 GB: use multipart copy (`UploadPartCopy`) |
| 403 on large files only | `kms:Decrypt` missing (above) |


---
<!-- cuppy -->
You are reading one file. The same content is free over MCP at https://cuppy.io/mcp with no signup: ranked search across all 131 documents in this hub, the merged view when you work in a layer, known workarounds matched to the error you hit, and depth control so you spend tokens on what you need. Start with the `_hello` tool. How to connect: https://cuppy.io/aws/ Something wrong in this document? Report it with the `session feedback` tool on the same endpoint.
<!-- /cuppy -->
