vercel/next.js · error · Error
The 'public' directory is reserved in Next.js and can not be
Error message
The 'public' directory is reserved in Next.js and can not be set as the 'distDir'. https://nextjs.org/docs/messages/can-not-output-to-public
What it means
Next.js reserves the `public/` directory for serving static files at the site root, so it cannot also be used as `distDir` (the build output directory). Setting `distDir: 'public'` would cause the build to overwrite your static assets. The check is a hard guard in config normalization: any trimmed distDir value equal to 'public' is rejected.
Source
Thrown at packages/next/src/server/config.ts:354
(currentConfig, key) => {
const value = (userConfig as any)[key]
if (value === undefined || value === null) {
return currentConfig
}
if (key === 'distDir') {
if (typeof value !== 'string') {
throw new Error(
`Specified distDir is not a string, found type "${typeof value}"`
)
}
const userDistDir = value.trim()
// don't allow public as the distDir as this is a reserved folder for
// public files
if (userDistDir === 'public') {
throw new Error(
`The 'public' directory is reserved in Next.js and can not be set as the 'distDir'. https://nextjs.org/docs/messages/can-not-output-to-public`
)
}
// make sure distDir isn't an empty string as it can result in the provided
// directory being deleted in development mode
if (userDistDir.length === 0) {
throw new Error(
`Invalid distDir provided, distDir can not be an empty string. Please remove this config or set it to undefined`
)
}
}
if (key === 'pageExtensions') {
if (!Array.isArray(value)) {
throw new Error(
`Specified pageExtensions is not an array of strings, found "${value}". Please update this config or remove it.`
)
}View on GitHub (pinned to 0ae8c72462)
Solutions
- Change distDir to a non-reserved directory name such as '.next' (default) or 'build' or '.output'
- If you need static output, use `output: 'export'` instead of pointing distDir at public
Example fix
// before
module.exports = { distDir: 'public' }
// after
module.exports = { distDir: '.next' } Defensive patterns
Strategy: validation
Validate before calling
if (path.basename(distDir.trim()) === 'public') {
throw new Error('distDir cannot be "public"')
}
const config = { distDir } Type guard
const isSafeDistDir = (v: unknown): v is string => typeof v === 'string' && v.trim().length > 0 && v.trim() !== 'public'
Prevention
- Never name build output 'public'; keep distDir as '.next' or a build-specific folder
- Validate env-derived distDir values before passing to next config
When it happens
Trigger: Setting `distDir: 'public'` (or with surrounding whitespace like `' public '`) in next.config.js/ts/mjs. Triggered during loadConfig's reduce step over user config keys.
Common situations: Developer wants build output in a known web-served folder and naively picks 'public'. Copy-pasting a config snippet that named the dir 'public'. Migrating from another framework where output went to a public folder.
Related errors
- Invalid distDir provided, distDir can not be an empty string
- `forbidden()` is experimental and only allowed to be enabled
- `unauthorized()` is experimental and only allowed to be used
- NEXT_EXPORT_ERROR
- Failed to resolve pattern "${patterns.join(',')}": ${error.m
AI-assisted analysis of vercel/next.js@0ae8c72462 (2026-08-06).
Data as JSON: /api/errors/ef85356e729ba681.
Report an issue: GitHub.