How to Fix: Route Handler with App Router returns 413 Request Entity Too Large
413 Request Entity Too Large in Next.js App Router: Fixing Route Handlers That Reject Large Form Uploads
Your App Router route handler is not broken because of your form logic. It fails because the incoming request body crosses a size boundary before your handler can safely process it, which triggers the classic 413 Request Entity Too Large response.
Table of Contents
In Next.js App Router, this usually appears when a user submits a large file, a multipart form, or a payload that exceeds what the runtime or deployment platform accepts for a single request. The result is confusing because the route handler looks correct, yet the request never fully reaches your business logic.
Understanding the Root Cause
The 413 error happens when the server, runtime, proxy, or hosting layer decides the request body is too large to accept. With App Router route handlers, this can be triggered by several layers:
- Platform request size limits on the deployment target.
- Serverless runtime constraints that make large uploads impractical or unsupported.
- Multipart form parsing that buffers too much data in memory.
- Using request.formData() for file uploads, which may force the runtime to parse the entire body before your code can stream or offload it.
The key technical detail is this: when you call request.formData(), the runtime typically needs to read and parse the full multipart payload. For small forms, that works fine. For large files, the body may exceed size limits before parsing completes. That is why developers often see a 413 even though the route handler code itself is simple.
This is especially common when trying to upload images, PDFs, videos, or large generated blobs through a Route Handler in the App Router. If the upload path relies on your Next.js server as the middleman, the request must first survive all body-size checks. If any layer refuses it, the request dies early.
In practice, the most reliable fix is to avoid sending large files through the route handler and instead upload them directly to object storage using a signed URL or a provider SDK flow. That removes your Next.js server from the hot path for large binary payloads.
Step-by-Step Solution
The safest production approach is to split the flow into two parts:
- Create a lightweight route handler that generates a temporary upload target.
- Upload the file directly from the browser to storage.
1. Create a route handler that returns a signed upload URL
This example uses a generic pattern. Your storage provider may be S3, Vercel Blob, Cloudinary, GCS, or another service.
import { NextResponse } from 'next/server'
export async function POST() {
// Generate a signed upload URL using your storage provider SDK
const signedUrl = await createSignedUploadUrl()
return NextResponse.json({ url: signedUrl })
}
async function createSignedUploadUrl() {
// Replace with your provider-specific implementation
return 'https://example-storage-upload-url'
}
2. Upload the file directly from the client
'use client'
import { useState } from 'react'
export default function UploadForm() {
const [status, setStatus] = useState('idle')
async function handleSubmit(event) {
event.preventDefault()
const file = event.target.file.files[0]
if (!file) return
setStatus('getting-upload-url')
const signedUrlRes = await fetch('/api/upload-url', {
method: 'POST'
})
const { url } = await signedUrlRes.json()
setStatus('uploading')
const uploadRes = await fetch(url, {
method: 'PUT',
body: file,
headers: {
'Content-Type': file.type || 'application/octet-stream'
}
})
if (!uploadRes.ok) {
setStatus('failed')
return
}
setStatus('done')
}
return (
<form onSubmit={handleSubmit}>
<input name="file" type="file" />
<button type="submit">Upload</button>
<p>Status: {status}</p>
</form>
)
}
3. Store only metadata in your Next.js route handler
After the direct upload succeeds, send a small JSON request to your app containing the uploaded file path, file name, MIME type, or any database metadata.
import { NextResponse } from 'next/server'
export async function POST(request) {
const body = await request.json()
const record = {
fileName: body.fileName,
fileUrl: body.fileUrl,
size: body.size,
mimeType: body.mimeType
}
// Save to database here
return NextResponse.json({ success: true, record })
}
4. If the payload is not a file, reduce request size
If you are not uploading files and still getting 413, inspect the body content. Large JSON payloads, base64 strings, and oversized rich text can trigger the same problem. In that case:
- Do not embed files as base64 inside JSON.
- Split the payload into smaller requests.
- Compress or restructure data before sending.
- Move large binary content to direct storage uploads.
5. Avoid request.formData() for large uploads when possible
This pattern often causes trouble for big files:
export async function POST(request) {
const formData = await request.formData()
const file = formData.get('file')
return Response.json({ ok: true })
}
For small files, it may work. For larger uploads, it can fail before completion because the platform must parse the full multipart body. If the file is large, use direct-to-storage uploads instead of routing the entire stream through the App Router.
6. Verify your hosting platform limits
Even correct code will fail if the deployment target imposes a hard body limit. Check the request body documentation for your host and storage provider. For Next.js projects deployed on managed platforms, proxy and serverless limits can be lower than what works locally. Review the relevant docs on Next.js documentation and your hosting provider’s request-size limits.
7. Test locally and in production with realistic file sizes
Many teams miss this because a small test image passes, but a real customer uploads a 20 MB PDF or a 200 MB video. Reproduce using actual file sizes, not placeholder payloads.
const fileInput = document.querySelector('input[type="file"]')
console.log(fileInput.files[0].size)
If the size is large enough to hit platform limits, the route handler approach is the wrong architecture for that request path.
Common Edge Cases
- Works locally but fails in production: local dev servers often behave differently from serverless or edge deployments. Production infrastructure may enforce stricter body limits.
- Sending base64 in JSON: base64 increases payload size significantly, often by roughly one-third, making 413 errors more likely.
- Using the Edge runtime: some upload flows are not a good fit for edge environments due to streaming and body handling constraints.
- Reverse proxy or CDN limits: the request may be rejected before Next.js sees it.
- Large multipart fields without files: even text-heavy multipart requests can overflow configured limits.
- Memory pressure during parsing: if the runtime buffers multipart data, large requests can fail even before explicit size validation appears in your code.
- Trying to validate too late: checking file size after request.formData() is often too late because the body has already been received and parsed.
If you must support large uploads, the durable pattern is straightforward: browser to storage directly, then small metadata request to Next.js.
FAQ
Can I increase the body size limit for App Router route handlers?
Sometimes there are framework- or platform-specific limits you can configure, but for large file uploads this is rarely the best fix. If your host has a hard request cap, configuration will not help. Direct uploads are usually the correct long-term solution.
Why does request.formData() fail for large files?
Because the runtime usually needs to consume and parse the full multipart/form-data body. If that payload exceeds the accepted size before parsing completes, the server responds with 413.
What is the best upload architecture for Next.js App Router?
Use your Route Handler only to authenticate the user, generate a signed upload target, and save metadata afterward. Upload the actual file directly from the client to blob or object storage.
That architecture avoids oversized request bodies, reduces memory usage, and makes your Next.js App Router application much more reliable for real-world file uploads.