serverActions
Tune the body size limit and the origins allowed to invoke Server Functions.
experimental?: { serverActions?: { allowedOrigins?: string[]; bodySizeLimit?: number | string } }Parameters
| Parameter | Type | Description |
|---|---|---|
$allowedOriginsoptional | string[]= undefined | Extra origin domains that may invoke Server Actions. Next.js compares the request origin with the host and rejects mismatches to prevent CSRF. Wildcard subdomains such as '*.my-proxy.com' are supported. If not provided, only the same origin is allowed. |
$bodySizeLimitoptional | number | string= '1mb' | Maximum size of the request body sent to a Server Action, as a byte count or any string the bytes package accepts, for example 1000, '500kb' or '3mb'. |
Errors
A Server Action request whose origin does not match the host or an allowedOrigins entry is rejected, and a request body over bodySizeLimit fails to parse.
Changelog
- PHP v14.0.0Server Actions became stable and are enabled by default; experimental.serverActions: true is only needed on Next.js 13.
Server Actions are POST requests to your own origin, so Next.js enforces a security boundary on them: the request Origin must match the host, and the body is capped at 1MB. Both checks are deliberately strict, and both are what this option relaxes.
When to reach for it
allowedOrigins is for deployments where the browser's origin legitimately differs from the host the server sees — a reverse proxy, a preview tunnel, or a custom domain in front of the app. Adding the proxy host is the fix for actions that work locally and fail with an origin mismatch behind infrastructure.
bodySizeLimit is for actions that accept a real payload: a form with an attached image, a pasted CSV, a batch of rows.
What trips people up
- The limit applies to the raw HTTP body, including the boundaries, part headers and field metadata that
multipart/form-dataadds. Leave 10–20 KB of headroom over your intended file size. - Every entry in
allowedOriginsis a host that may drive mutations in your app. Add the specific proxy, not a wildcard you do not control. - Raising the limit to tens of megabytes turns every action into a memory risk. Upload large files directly to object storage with a signed URL and pass only the key through the action.
Example
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
serverActions: {
bodySizeLimit: '2mb',
allowedOrigins: ['my-proxy.com', '*.my-proxy.com'],
},
},
}
export default nextConfigWhen to use it
- Accept a form that carries an image or CSV larger than the default 1MB body limit.
- Let Server Actions run behind a reverse proxy or preview tunnel whose hostname differs from the internal host.
- Lower the body limit on a public form to reduce the cost of a flood of oversized requests.
Frequently asked questions
How do I fix Body exceeded 1 MB limit in a Server Action?
Set experimental.serverActions.bodySizeLimit in next.config to a larger value, such as '2mb', and restart the dev server. Remember the limit covers the whole multipart body, so leave 10–20KB above the largest file you intend to accept.
Why do my Server Actions fail with an origin mismatch behind a proxy?
Next.js compares the request origin against the host to block CSRF, and a proxy that rewrites the host breaks that comparison. Add the public hostname to experimental.serverActions.allowedOrigins, or configure the proxy to forward the original host headers.
Do I still need experimental.serverActions to use Server Actions?
No. Server Actions became stable in Next.js 14 and are enabled by default; the option only exists now to configure allowedOrigins and bodySizeLimit. The boolean form was for Next.js 13.
More examples
Raising the limit for an avatar upload
The client validates that the file is at most 4MB, but the request that carries it is larger: multipart boundaries, part headers and the other form fields all count toward the limit. The extra 500KB is the headroom that stops a valid 4MB file from being rejected.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
serverActions: {
// 4MB of image plus multipart overhead
bodySizeLimit: '4.5mb',
},
},
}
export default nextConfigThe action the limit applies to
This is the code the body size limit governs. The whole FormData crosses the wire in one POST, so the file plus every other field must fit under bodySizeLimit. For anything much bigger, hand the browser a signed upload URL and pass only the resulting key to the action.
'use server'
import { updateTag } from 'next/cache'
import { db } from '@/lib/db'
import { storage } from '@/lib/storage'
export async function uploadAvatar(userId: string, formData: FormData) {
const file = formData.get('avatar')
if (!(file instanceof File)) {
return { error: 'No file provided' }
}
const key = await storage.put(`avatars/${userId}`, file)
await db.users.update(userId, { avatarKey: key })
updateTag(`user-${userId}`)
return { ok: true }
}Behind a reverse proxy
The container sees a host like next:3000 while the browser sends Origin: https://app.example.com, so the CSRF check rejects every action. Naming the public hostnames restores them. The alternative fix is to make the proxy forward the correct host headers — prefer that when you control the proxy.
import type { NextConfig } from 'next'
const nextConfig: NextConfig = {
experimental: {
serverActions: {
allowedOrigins: ['app.example.com', 'preview.example.com'],
},
},
}
export default nextConfig
Discussion