Skip to content

AWS S3 & CloudFront File Upload Limits Summary | Multipart & Presigned URLs

Category: Cloud / AWS
This article is currently available in Japanese only. We are working on translations.

When building a file upload feature using AWS, S3, CloudFront, API Gateway, and Lambda each have different size limits. Understanding which layer becomes a bottleneck is extremely important. This article explains the limit values for each service, how to use multipart upload and presigned URLs for handling large files, and provides implementation examples in PHP.

S3 upload methods and sizes PUT (single) ≤ 5 GB Multipart upload 5 MB ~ 5 TB / object Object size limit (S3) 5 TB max Note: CloudFront / API Gateway / Lambda have separate body limits
Diagram: S3 upload size tiers (single PUT 5GB / multipart 5TB)

Amazon S3 Upload Limits

Object upload size limits to S3 vary depending on the method used.

Upload method Maximum size Remarks
PUT Object (single) 5 GB Upload limit per request
Multipart Upload 5 TB Maximum size per object
Per part Minimum 5 MB to maximum 5 GB Only the final part may be less than 5 MB
Number of Parts Maximum 10,000 parts Multipart Upload Limit

AWS recommends multipart upload for files larger than 100 MB. From the perspective of efficient retransmission during network failures and improved throughput through parallel transfers, it should be actively used for large files.

Cases Requiring Multipart Upload

Multipart upload is a method where a single object is divided into multiple parts, each sent as an independent request, and then combined at the end. It is effective in the following scenarios.

  • <strong>100 MB or larger files</strong>: This is the multipart upload threshold recommended by AWS.
  • <strong>Unstable network environments</strong>: Even if an error occurs mid-transfer, only the failed parts need to be retransmitted.
  • <strong>Maximize throughput</strong>: Upload multiple parts in parallel to improve transfer speed.
  • <strong>Pause and resume uploads</strong>: Save the Upload ID to resume across sessions.

The multipart upload process consists of three major steps.

  1. <strong>Initiate</strong> (CreateMultipartUpload): Obtain the Upload ID
  2. <strong>Send parts</strong> (UploadPart): Upload each part and record the ETag
  3. <strong>Complete</strong> (CompleteMultipartUpload): Send a list of part numbers and ETags to finalize the object

If you cancel midway without calling <code>AbortMultipartUpload</code>, incomplete parts will continue to be charged as storage fees. It is strongly recommended to set up a lifecycle policy on your S3 bucket to "delete incomplete multipart uploads after N days."

Presigned URL expiration and size

Using a signed URL (Presigned URL) allows clients without S3 access permissions (such as browsers or mobile apps) to upload files directly to S3. Since the server is not involved as an intermediary, large files can be handled efficiently.

Item Restrictions & Specifications
Maximum expiration (issued by IAM user) 7 days (604,800 seconds)
Maximum expiration (issued by IAM role) Within the role's session time (maximum 12 hours)
Maximum uploadable file size Maximum 5 GB for single PUT
Support for multipart Issue individual Presigned URLs for each part

A Presigned URL is generated on the backend and returned to the client, which then sends a PUT request directly to that URL. Since the URL contains a signature, it succeeds only when uploading the correct file within the expiration period.

CloudFront body size limit

When forwarding requests through CloudFront to an origin (such as S3 or EC2), there are size limits on the request body.

Settings Default Value Maximum value
Request Body Size (Default) 1 MB Can be changed in distribution settings
When Using Lambda@Edge 1 MB 1 MB (unchangeable)
In the case of CloudFront Functions Request body is not accessible

In CloudFront distribution settings, you can enable "Allow requests with body" and raise the limit, but note that Lambda@Edge has a non-changeable 1 MB limit. For uploading large files, it is recommended to adopt an architecture that bypasses CloudFront and uploads directly from the client to S3 using Presigned URLs.

API Gateway Payload Limit

API Gateway (both REST API and HTTP API) has a payload size limit.

API Type Maximum payload size Remarks
REST API 10 MB The same applies when binary support is enabled
HTTP API 10 MB
WebSocket API 128 KB (message) / 32 KB (frame)

API Gateway's 10 MB limit is classified as an AWS service quota and cannot be raised. Uploading files exceeding 10 MB via API Gateway is considered a design flaw; consider migrating to the Presigned URL pattern.

File Limits via Lambda

When receiving files in a Lambda function, there is a size limit on the event payload passed from API Gateway. Additionally, Lambda itself has the following constraints.

Restriction Items Value
Synchronous call (Request) payload 6 MB
Synchronous call (Response) payload 6 MB
Asynchronous Call Payload 256 KB
Storage capacity of <code>/tmp</code> directory Default 512 MB (maximum 10 GB)
Maximum execution time 15 minutes

When processing files in Lambda, temporary files are written to <code>/tmp</code>. The default is 512 MB, but ephemeral storage can be extended up to 10 GB through Lambda configuration (additional charges apply).

Code example for S3 multipart upload in PHP

This is an implementation example of multipart upload using AWS SDK for PHP (v3). Using the SDK's <code>MultipartUploader</code> class automatically handles chunk splitting, retries, and completion processing.

use Aws\S3\S3Client;
use Aws\S3\MultipartUploader;
use Aws\Exception\MultipartUploadException;

$s3 = new S3Client([
    'region'  => 'ap-northeast-1',
    'version' => 'latest',
]);

$uploader = new MultipartUploader($s3, '/path/to/large-file.mp4', [
    'bucket'          => 'your-bucket-name',
    'key'             => 'uploads/' . basename('/path/to/large-file.mp4'),
    'before_initiate' => function (\Aws\Command $command) {
        // アップロード開始前のフック
    },
    'before_upload'   => function (\Aws\Command $command) {
        // 各パートアップロード前のフック(プログレス表示など)
    },
    'concurrency'     => 5,    // 並列アップロード数
    'part_size'       => 10 * 1024 * 1024, // 1パート = 10 MiB
]);

try {
    $result = $uploader->upload();
    echo 'アップロード完了: ' . $result['ObjectURL'];
} catch (MultipartUploadException $e) {
    // 失敗したパートから再開する例
    $uploader = new MultipartUploader($s3, '/path/to/large-file.mp4', [
        'state' => $e->getState(),
    ]);
    $result = $uploader->upload();
}

Here is how to issue a Presigned URL and allow clients to upload directly to S3.

use Aws\S3\S3Client;

$s3 = new S3Client([
    'region'  => 'ap-northeast-1',
    'version' => 'latest',
]);

// 署名付きURLを生成(有効期限: 15分)
$cmd = $s3->getCommand('PutObject', [
    'Bucket'       => 'your-bucket-name',
    'Key'          => 'uploads/' . uniqid('', true) . '.jpg',
    'ContentType'  => 'image/jpeg',
]);

$request = $s3->createPresignedRequest($cmd, '+15 minutes');
$presignedUrl = (string) $request->getUri();

// このURLをクライアントに返す
// クライアントはこのURLに PUT リクエストでファイルを直接送信する
echo json_encode(['upload_url' => $presignedUrl]);

Architecture selection guidelines

  • <strong>Up to 10 MB</strong>: Can be implemented simply with API Gateway → Lambda → S3
  • <strong>10 MB–100 MB</strong>: Direct upload from client to S3 using Presigned URLs is recommended
  • <strong>100 MB–5 GB</strong>: Achieve stable transfers with Presigned URL + multipart upload
  • <strong>Over 5 GB</strong>: Multipart upload is mandatory (PUT alone is not sufficient)

Test Procedure Using DevLab Threshold Files

To verify <code>S3</code> upload settings in practice, you need test files of precise sizes. Using DevLab's boundary value test files allows you to efficiently verify behavior around specific sizes.

  1. Download a file of the desired size from the <a href="/ja/files/threshold/">boundary value test files list</a> on DevLab.
  2. When validating the multipart switching threshold, you can also use the large-size version of <a href="/ja/files/images/png/">PNG test images</a>.
  3. Upload the downloaded file using the <code>aws s3 cp</code> command or the SDK's <code>PutObject</code> / <code>MultipartUploader</code>, and verify success or failure with files around the size limit.

Test files for this article

  • <a href="/ja/files/threshold/" class="text-primary-600 dark:text-primary-400 hover:underline">Boundary Value Test File List</a> — For validating S3, API Gateway, and Lambda limits
  • <a href="/ja/files/threshold/10mb/" class="text-primary-600 dark:text-primary-400 hover:underline">10MB Boundary Value Test Set</a> — Check just before and after the 10 MB API Gateway limit
  • <a href="/ja/files/threshold/25mb/" class="text-primary-600 dark:text-primary-400 hover:underline">25MB Threshold Test Set</a> — For verifying behavior around the multipart recommended line
  • <a href="/ja/files/images/png/" class="text-primary-600 dark:text-primary-400 hover:underline">PNG Test Images</a> — Verify image upload pipeline functionality

Related articles

  • <a href="/ja/blog/how-to-test-upload-limit/" class="text-primary-600 dark:text-primary-400 hover:underline">How to Properly Test File Upload Size Limits</a>
  • <a href="/ja/blog/php-file-upload/" class="text-primary-600 dark:text-primary-400 hover:underline">How to implement file upload in PHP | Complete guide to validation, storage, and security</a>
  • <a href="/ja/blog/multipart-form-data-overhead/" class="text-primary-600 dark:text-primary-400 hover:underline">Calculate multipart/form-data overhead accurately</a>
  • <a href="/ja/blog/mb-vs-mib-file-size/" class="text-primary-600 dark:text-primary-400 hover:underline">MB and MiB Are Different! Pitfalls of File Size Units</a>

Frequently Asked Questions

What is the maximum file size for a single S3 PUT request upload?

A single PUT operation supports up to 5GB maximum. For larger files, use multipart upload, which supports up to 5TB.

What is the expiration time for S3 presigned URLs?

The default is 15 minutes, with a maximum of 7 days (604800 seconds). This is the upper limit when generated with IAM user credentials.

How do upload size limits change when going through CloudFront?

The default CloudFront request body size limit is 0 for GET and a maximum of 20 MB for POST/PUT. A design that uploads large files directly to S3 is recommended.