Multipart upload for large files
For large files, multipart upload is dramatically more reliable than a single PUT:
- Parts upload in parallel — much higher throughput.
- A failed part retries individually — no need to restart the whole transfer.
- Required for objects larger than 5 GB.
Every modern AWS SDK and the AWS CLI switch to multipart automatically. This recipe shows the easy path for the common SDKs and the full low-level protocol when you need fine-grained control.
Easy mode
AWS CLI
The AWS CLI auto-detects file size and switches to multipart at 8 MB by default:
aws --endpoint https://s3.filebase.io s3 cp ./video.mp4 s3://my-bucket/
Tune the threshold and chunk size globally:
aws configure set default.s3.multipart_threshold 64MB
aws configure set default.s3.multipart_chunksize 64MB
aws configure set default.s3.max_concurrent_requests 16
AWS SDK for JavaScript v3
import { Upload } from '@aws-sdk/lib-storage';
import { createReadStream } from 'node:fs';
const upload = new Upload({
client: s3,
params: {
Bucket: 'my-bucket',
Key: 'video.mp4',
Body: createReadStream('./video.mp4'),
},
partSize: 8 * 1024 * 1024, // 8 MB parts
queueSize: 4, // 4 in-flight uploads
});
upload.on('httpUploadProgress', (p) => {
console.log(`${p.loaded} / ${p.total}`);
});
await upload.done();
AWS SDK for Python (boto3)
from boto3.s3.transfer import TransferConfig
config = TransferConfig(
multipart_threshold=8 * 1024 * 1024,
multipart_chunksize=8 * 1024 * 1024,
max_concurrency=4,
)
s3.upload_file('./video.mp4', 'my-bucket', 'video.mp4', Config=config)
AWS SDK for Go v2
import "github.com/aws/aws-sdk-go-v2/feature/s3/manager"
uploader := manager.NewUploader(client, func(u *manager.Uploader) {
u.PartSize = 8 * 1024 * 1024
u.Concurrency = 4
})
f, _ := os.Open("./video.mp4")
defer f.Close()
uploader.Upload(ctx, &s3.PutObjectInput{
Bucket: aws.String("my-bucket"),
Key: aws.String("video.mp4"),
Body: f,
})
Manual multipart, by hand
Write the three calls yourself when you need:
- To upload parts from many sources (e.g. multipart browser upload, distributed workers).
- Custom retry logic.
- Resumable uploads with checkpoints.
import {
CreateMultipartUploadCommand,
UploadPartCommand,
CompleteMultipartUploadCommand,
AbortMultipartUploadCommand,
} from '@aws-sdk/client-s3';
async function multipartUpload(
bucket: string,
key: string,
parts: Buffer[],
) {
// 1. Start the upload
const { UploadId } = await s3.send(
new CreateMultipartUploadCommand({
Bucket: bucket,
Key: key,
ContentType: 'video/mp4',
}),
);
if (!UploadId) throw new Error('No UploadId');
try {
// 2. Upload each part (5 MB minimum, except the last)
const uploaded: { ETag: string; PartNumber: number }[] = [];
for (let i = 0; i < parts.length; i++) {
const partNumber = i + 1;
const { ETag } = await s3.send(
new UploadPartCommand({
Bucket: bucket,
Key: key,
UploadId,
PartNumber: partNumber,
Body: parts[i],
}),
);
if (!ETag) throw new Error(`Part ${partNumber} returned no ETag`);
uploaded.push({ ETag, PartNumber: partNumber });
}
// 3. Complete
await s3.send(
new CompleteMultipartUploadCommand({
Bucket: bucket,
Key: key,
UploadId,
MultipartUpload: { Parts: uploaded },
}),
);
} catch (err) {
// 4. On error, abort to free part storage
await s3.send(
new AbortMultipartUploadCommand({
Bucket: bucket,
Key: key,
UploadId,
}),
);
throw err;
}
}
Resumable uploads
The full multipart protocol naturally supports resume:
- On the first attempt,
CreateMultipartUploadand persist theUploadIdsomewhere (database, local file). - As parts succeed, persist the
(PartNumber, ETag)pair. - On retry after a crash:
- Read the persisted
UploadIdand completed parts. - Call
ListParts(UploadId)to confirm what's actually uploaded. - Skip already-uploaded parts; resume from the next.
- Call
CompleteMultipartUploadwith the full list.
- Read the persisted
Don't forget cleanup: if the user cancels permanently, call AbortMultipartUpload to free part storage. Otherwise orphaned parts count toward your storage quota.
Choosing part size
| File size | Recommended part size |
|---|---|
| < 100 MB | Single PUT, no multipart |
| 100 MB – 1 GB | 8 MB |
| 1 GB – 10 GB | 16 MB |
| 10 GB – 100 GB | 64 MB |
| 100 GB – 1 TB | 128 MB |
| > 1 TB | 256 MB |
Constraints:
- 5 MiB minimum per part (except the last).
- 5 GiB maximum per part.
- 10,000 parts maximum per upload.
For the largest objects, larger parts reduce overhead. For smaller objects, smaller parts give finer-grained retry.
Cleaning up failed uploads
Orphan multipart uploads count toward your storage. List them periodically:
aws --endpoint https://s3.filebase.io s3api list-multipart-uploads --bucket my-bucket
Abort each by ID and key:
aws --endpoint https://s3.filebase.io s3api abort-multipart-upload \
--bucket my-bucket \
--key video.mp4 \
--upload-id <id>