How to Handle the AWS API Gateway 10MB Upload Limit

How to Handle the AWS API Gateway 10MB Upload Limit

The support ticket says, “Uploads over 10MB fail.” There’s no stack trace and no error from the app. The gateway rejected the request before it ever reached your code, and changing a setting in your account won’t change that limit.

Teams building serverless apps on AWS eventually run into the AWS API Gateway file upload size limit, often through a ticket that says exactly this. The 10 MB limit is fixed, so there’s no application setting you can change to increase it.

AWS API Gateway enforces a hard 10MB payload limit on REST and HTTP APIs, and no configuration raises it. Uploads bigger than that must bypass the gateway using presigned S3 URLs, S3 multipart upload, or a managed upload service. The gateway then handles only authorization and metadata, which is also the cheaper and faster architecture.

This article covers why the limit exists, the two workarounds teams try first and why they fall short, and the presigned URL pattern that actually solves it.

Key Takeaways

  • API Gateway’s 10MB payload cap applies to both REST and HTTP APIs, and there is no setting that raises it.
  • Lambda’s synchronous invocation payload cap is 6MB, and binary bodies routed through the gateway ride as base64, which inflates size by roughly 1.33x.
  • Combined, the practical ceiling for gateway-routed binary uploads lands closer to 4-7MB of real file, well under the 10MB headline number.
  • Presigned S3 URLs let a client upload directly to S3 using time-boxed credentials your API issues, without the file passing through the gateway at all.
  • S3 multipart upload carries objects up to 5TB, split into parts uploaded in parallel, each with its own retry.

The Limit and Why It Exists

The limit is simple: API Gateway has a 10 MB payload limit for both REST APIs and HTTP APIs. It’s not a default that you can increase later. It’s a hard limit, so changing your configuration or opening a support ticket won’t raise it.

The reason makes more sense when you look at what a gateway is designed to do. API Gateway handles things like routing, authentication, and sending requests to your backend. It wasn’t built to move large files.

S3, on the other hand, is built for storing and transferring large objects. It supports objects up to 5 TB and is designed for large-scale data transfers.

Instead of trying to push large files through the 10 MB gateway limit, it’s better to route the file around the gateway and use each service for what it does best.

That becomes even clearer when you look at what happens when teams try to work around the limit without changing the upload path.

Anti-Patterns, Base64 Bloat and Lambda Buffers

Two common approaches show up in questions about an API for uploading files on AWS, and both look like they should work but fall short.

The first is sending binary uploads through Lambda behind an API Gateway. Lambda has its own synchronous payload limit of 6 MB, which is already lower than API Gateway’s 10 MB limit. Binary request bodies can also be base64-encoded as they move through API Gateway, increasing their size by about 33%. So a 5 MB file can become roughly 6.65 MB before Lambda receives it, which can push it past Lambda’s limit.

When you combine these limits, the practical upload size can be much lower than the 10 MB API Gateway limit, depending on how the request is handled.

The second approach is increasing every timeout and buffer setting you can find and hoping one of them is the problem. It won’t help. The 10 MB API Gateway limit is a hard platform limit, not a setting you can increase with Lambda memory, timeouts, or gateway configuration.

Both approaches make the same mistake: trying to send more data through a component that wasn’t designed to handle large file transfers.

The solution isn’t a bigger pipe through the API Gateway. It’s a different upload path.

The Presigned URL Pattern

A presigned URL takes a different approach instead of trying to work around the gateway limit. The client first asks your API for permission to upload. Your API then creates a short-lived, signed URL that points directly to S3. The client uploads the file using that URL.

The file itself never passes through the API Gateway or Lambda.

This is also the practical answer to how to set up a file upload API with your own S3 bucket at scale: let Lambda generate the presigned URL, but don’t make Lambda receive the file. The actual file upload goes straight to S3.

Diagram showing routing around the aws api gateway file upload size limit with direct-to-storage uploads.

import boto3

import json

s3 = boto3.client("s3")

BUCKET = "your-upload-bucket"

def lambda_handler(event, context):

    body = json.loads(event["body"])

    key = body["filename"]

    presigned_url = s3.generate_presigned_url(

        ClientMethod="put_object",

        Params={"Bucket": BUCKET, "Key": key, "ContentType": body.get("contentType", "application/octet-stream")},

        ExpiresIn=300,  # 5 minutes

    )

    return {

        "statusCode": 200,

        "body": json.dumps({"uploadUrl": presigned_url, "key": key}),

    }

 

// Client side: request the URL, then PUT the file straight to S3

async function uploadFile(file) {

  const res = await fetch("/api/upload-url", {

    method: "POST",

    body: JSON.stringify({ filename: file.name, contentType: file.type }),

  });

  const { uploadUrl } = await res.json();

  await fetch(uploadUrl, {

    method: "PUT",

    headers: { "Content-Type": file.type },

    body: file,

  });

}

The gateway now only handles a small JSON request and response. The file itself, no matter how large it is, goes directly to S3 through a connection designed to handle large uploads.

Filestack discord

A single PUT request works well for many files. For larger files, splitting the upload into smaller parts makes the process more reliable.

Multipart for the Truly Large

S3 multipart upload splits a large file into smaller parts, uploads each part separately, and puts them back together once all the parts arrive. It supports objects up to 5 TB, and parts can be uploaded in parallel and retried individually if something goes wrong.

This is the practical answer to what’s the best way to handle multipart or resumable uploads for large files: don’t retry the entire file when one part fails. Retry only the part that failed.

The same approach helps answer what API supports uploading files up to 5 GB reliably on unstable networks. The smaller retry units make large uploads much more reliable. If a 2 GB upload fails at 90% during one large PUT, you may have to start again. With the same file split into 5 MB parts, you only need to retry the part that was interrupted.

Presigned URLs and multipart uploads solve the file transfer problem well. The trade-off is that building and maintaining this infrastructure yourself takes ongoing work, even after the initial setup is working.

The Managed Route, The Pattern Productized

The managed version of this approach is a file upload API that handles the upload infrastructure for you. It can issue upload credentials, support chunked uploads for files up to 5 GB, and keep your gateway focused on handling JSON requests.

Instead of building and maintaining the presigning Lambda, client-side retry logic, and multipart upload handling yourself, you can use one integration that follows the same direct-upload approach.

Filestack provides direct uploads with chunked transfers, progress events, and an embeddable picker. This is useful if you want reliable file uploads without building the entire upload system from scratch.

For more on authentication and content types, see the file upload API guide. You can also check the large file upload guide for handling larger files and the Filestack S3 integration docs for the direct-to-S3 setup specifically.

Now that we’ve covered both approaches, here’s a quick summary of the key points.

Conclusion: Let the Gateway Serve JSON

The 10 MB limit isn’t going to change, so trying to work around it with bigger buffers or longer timeouts only wastes time.

The better fix is architectural: create a presigned URL, let the client upload directly to S3, and keep API Gateway focused on what it’s good at, such as authentication, routing, and small JSON requests.

It’s also a simpler and more efficient path because the file doesn’t have to pass through your gateway and backend first.

Try the presigned upload flow, or a managed alternative, this sprint. Either way, you’re moving the file data away from a component that wasn’t designed to carry large files.

Frequently Asked Questions

Can the API Gateway 10MB limit be increased?

No. It’s a hard limit on both REST and HTTP APIs, and no configuration or support request raises it.

Why do uploads under 10MB still fail through Lambda?

Base64 encoding inflates binary bodies by roughly 1.33x on the way through the gateway, and Lambda’s synchronous payload cap sits at 6MB, tighter than the gateway’s own limit.

What is the right pattern for large uploads on AWS?

Presigned direct-to-S3 uploads, or a managed upload service built on the same pattern. Either way, the gateway should only handle metadata, not file bytes.

Read More →