413 Request Entity Too Large: How to Fix Upload Size Limits
A 413 means a request body — usually a file upload — was bigger than a server allows. Where the limits live (Nginx client_max_body_size, Express body parsers, Next.js, Cloudflare, serverless platforms), how to raise them, and why large files should skip your server entirely.
413 Request Entity Too Large (also "Payload Too Large" or "Content Too Large") means the server refused the request because the body was bigger than it allows. It almost always happens on a file upload or a large form/JSON submission.
The tricky part: there are often several layers between the browser and your code, each with its own limit. You need to find which one said no.
Where the limit can be
Browser → Cloudflare → Nginx/Caddy → your app's body parser → your code
Nginx (the most common)
Nginx's default client_max_body_size is just 1 MB. Uploading a phone photo is enough to hit it.
server {
client_max_body_size 25M;
...
}
Reload after changing: sudo nginx -t && sudo systemctl reload nginx. The 413 page looks like plain Nginx: 413 Request Entity Too Large with nginx underneath. (What is Nginx?)
Caddy
No body size limit by default. If you've set one with request_body { max_size ... }, adjust it. (What is Caddy?)
Express
express.json() defaults to 100 KB:
app.use(express.json({ limit: '2mb' }))
app.use(express.urlencoded({ extended: true, limit: '2mb' }))
For file uploads, use a multipart parser like multer with its own limits.fileSize.
Next.js
Server Actions default to a 1 MB body. Raise it in next.config.js:
module.exports = {
experimental: { serverActions: { bodySizeLimit: '5mb' } },
}
API routes on serverless platforms have their own payload limits.
Cloudflare
Uploads through Cloudflare's proxy are limited by plan — 100 MB on Free and Pro. Above that you get a 413 from Cloudflare itself. (What is Cloudflare?)
Serverless platforms
Serverless functions typically cap request bodies at a few megabytes (Vercel's is about 4.5 MB). You can't raise it — the platform is telling you to upload differently.
How to find which layer it is
- Look at the 413 response in DevTools → Network. Nginx, Cloudflare and frameworks each have recognisable error pages or headers. (Browser developer tools)
- Check whether your app's logs show the request at all. If not, something in front rejected it.
- Try from the server itself with curl, bypassing the proxy. (What is curl?)
The better fix for big files: don't send them through your server
Raising limits works for modest sizes, but routing large files through your app is slow, ties up server memory and is fragile.
The standard approach is a presigned upload URL: your app gives the browser a short-lived URL, and the browser uploads directly to object storage (S3, R2 and similar). Your server only handles a small request. No 413, no timeouts, no memory spikes. (Direct uploads with presigned URLs, Where should user uploads go?)
Also check the client
- Compress images in the browser before upload — a 12 MB phone photo can become a 500 KB image with no visible difference. (Optimize images for the web)
- Validate size before uploading and show a friendly message, rather than letting the server reject it.
Set limits deliberately
Don't remove limits entirely. They protect you from someone sending gigabytes to tie up your server. Choose a sensible maximum for each kind of upload — avatars 5 MB, documents 25 MB — and enforce it in your code too.
EasySpawn puts your app behind a reverse proxy with sensible upload limits, and gives you object storage for big files so they never need to pass through your app. See how it works or join the waitlist.
Related: Direct-to-Storage Uploads With Presigned URLs · Where Should User Uploads Go? · HTTP Status Codes Explained · What Is Nginx?
Keep reading
npm run build Fails but npm run dev Works: Why and How to Fix It
Development mode is forgiving; production builds are strict. The common reasons a build fails when dev works — TypeScript and lint errors, case-sensitive imports, missing environment variables, server-only code in the browser, prerendering errors and memory — with the fix for each.
"exec format error" in Docker: ARM vs x86 Images Explained
exec format error almost always means a container image built for one CPU architecture (ARM, like Apple Silicon Macs) is running on another (x86/amd64 servers), or vice versa. How to check, build for the right platform with --platform and buildx, and the other cause: scripts without a shebang or with Windows line endings.