MENU
Compiler Configurations
1. distDir
The distDir option allows you to specify a custom name for the build output directory instead of the default .next folder. This is useful when you need to integrate with deployment systems that expect a specific directory name or when working with monorepos where consistent naming is important.
To configure a custom build directory, add the distDir config to your next.config.js:
module.exports = {
distDir: 'build',
}
After setting this configuration, when you run next build, Next.js will create a build directory instead of .next. This is particularly useful when:
- Your deployment platform expects a specific folder name (e.g., some CI/CD systems look for a "build" or "dist" folder)
- You're migrating from Create React App which uses "build" by default
- You want consistent naming across multiple projects in a monorepo
Important: The distDir should not leave your project directory. For example, ../build is an invalid directory and will cause build errors.
2. eslint
The eslint configuration controls how Next.js handles ESLint during production builds. By default, Next.js fails production builds when ESLint errors are present, encouraging code quality and consistency.
To disable the built-in linting step (not recommended), you can configure:
module.exports = {
eslint: {
// Warning: This allows production builds to successfully complete even if
// your project has ESLint errors.
ignoreDuringBuilds: true,
},
}
This configuration is useful in scenarios where:
- You have ESLint configured to run in a separate part of your workflow (CI/CD pipeline)
- You're using pre-commit hooks to enforce linting
- You're gradually introducing ESLint to a large codebase
- You need emergency deployments despite minor linting issues
Best Practice: Instead of disabling ESLint entirely, consider fixing the errors or using ESLint's // eslint-disable-next-line comments for specific exceptions.
3. generateBuildId
The generateBuildId function allows you to provide a custom build identifier instead of Next.js's automatically generated one. This is crucial for deployments where the same build needs to be used across multiple containers or when you need consistent build IDs across different environments.
module.exports = {
generateBuildId: async () => {
// Use Git commit hash for consistent build IDs
return process.env.GIT_HASH || 'dev-build'
},
}
Common strategies for generating build IDs:
// Using Git commit hash
generateBuildId: async () => {
const { execSync } = require('child_process')
return execSync('git rev-parse HEAD').toString().trim()
}
// Using timestamp
generateBuildId: async () => {
return new Date().toISOString().replace(/[:.]/g, '-')
}
// Using environment variables
generateBuildId: async () => {
return process.env.BUILD_NUMBER || `build-${Date.now()}`
}
This is particularly important for:
- Container orchestration where multiple instances need the same build ID
- Blue-green deployments
- CDN cache invalidation strategies
- Debugging and rollback scenarios
4. mdxRs
The mdxRs option enables the experimental Rust-based MDX compiler, which provides significantly faster compilation times for MDX files compared to the JavaScript-based compiler.
const withMDX = require('@next/mdx')()
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['ts', 'tsx', 'mdx'],
experimental: {
mdxRs: true,
},
}
module.exports = withMDX(nextConfig)
The Rust compiler offers several advantages:
- Faster compilation times, especially for large MDX files
- Better performance during development hot reloading
- Improved memory efficiency
- Enhanced error messages and debugging
This is particularly beneficial for:
- Documentation sites with many MDX files
- Blogs with extensive markdown content
- Component libraries with MDX-based documentation
- Large-scale content management systems
Note: This is an experimental feature and may have compatibility differences with the standard MDX compiler.
5. pageExtensions
The pageExtensions option allows you to modify which file extensions Next.js recognizes as pages. By default, Next.js accepts .tsx, .ts, .jsx, and .js files.
const withMDX = require('@next/mdx')()
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'md', 'mdx'],
}
module.exports = withMDX(nextConfig)
Common use cases include:
// Supporting MDX pages
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'mdx']
// Supporting Vue files (with custom webpack config)
pageExtensions: ['js', 'jsx', 'ts', 'tsx', 'vue']
// Restricting to TypeScript only
pageExtensions: ['ts', 'tsx']
// Adding custom extensions
pageExtensions: ['page.tsx', 'page.ts'] // Only files ending in .page.tsx/.page.ts
This is useful for:
- Documentation sites using MDX
- Restricting page creation to specific patterns
- Integrating with other templating systems
- Enforcing naming conventions in large teams
Important: Changing page extensions affects both the pages/ and app/ directories.
6. productionBrowserSourceMaps
Source maps are enabled by default during development but disabled in production to prevent exposing your source code. The productionBrowserSourceMaps option allows you to enable them in production builds.
module.exports = {
productionBrowserSourceMaps: true,
}
When enabled, source maps provide several benefits:
- Better debugging in production environments
- Meaningful stack traces in error monitoring tools
- Easier identification of performance bottlenecks
- Improved development experience when testing production builds
However, there are important considerations:
- Security: Source maps expose your original source code to anyone who can access them
- Performance: Increases build time and memory usage during compilation
- Bundle Size: Source map files are additional assets that need to be served
Best practices for production source maps:
- Use them only in staging environments or for debugging specific issues
- Configure your server to restrict access to .map files
- Consider using error monitoring services that can handle source maps securely
- Upload source maps to monitoring tools without serving them to end users
7. reactCompiler
The reactCompiler option enables support for the experimental React Compiler, which automatically optimizes component rendering by reducing the need for manual memoization with React.memo, useMemo and useCallback.
First, install the required plugin:
# Install the babel plugin
npm install babel-plugin-react-compiler
Then enable it in your configuration:
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
reactCompiler: true,
},
}
export default nextConfig
The React Compiler provides several optimization modes:
// Opt-in mode - only compile annotated components
const nextConfig = {
experimental: {
reactCompiler: {
compilationMode: 'annotation',
},
},
}
// Then annotate specific components
export default function MyComponent() {
'use memo'
// Component will be optimized
return <div>Hello World</div>
}
You can also opt-out specific components:
export default function ProblematicComponent() {
'use no memo'
// Component will not be optimized
return <div>Complex logic here</div>
}
Benefits of the React Compiler:
- Automatic memoization of expensive calculations
- Reduced re-renders and improved performance
- Less manual optimization code needed
- Future-proofing for React's concurrent features
Note: This is experimental and may cause slightly slower builds compared to the default Rust-based compiler.
8. turbopack
Turbopack is a new bundler developed by Vercel (the creators of Next.js), designed as a faster, modern replacement for Webpack in the JavaScript and TypeScript ecosystem—especially for Next.js projects.
Key Features of Turbopack:
- Built-in support for common needs like compiling modern JavaScript and handling CSS.
- Incremental bundling: Only re-bundles the parts of your app that changed, making development much faster.
- Rust-based: Written in Rust for performance, offering significant speed improvements over JavaScript-based bundlers like Webpack.
- Native support for Next.js: Deep integration with Next.js features and configurations.
- No manual loader setup required: For most common use cases, Turbopack handles things without needing explicit configuration (like babel-loader, css-loader, etc.).
Benefits of Turbopack:
- Significantly faster development builds
- Improved hot module replacement (HMR)
- Better memory efficiency
- Native support for modern JavaScript features
Current Limitations:
- Still in alpha or beta for many use cases.
- Limited support for the full Webpack loader API.
- Only supports JavaScript-returning loaders; others (e.g., image or stylesheet loaders) may not work yet.
In summary, Turbopack is Vercel's next-generation bundler, optimized for speed and seamless integration with Next.js, aiming to eventually replace Webpack in most use cases.
The turbopack configuration allows you to customize Turbopack, Next.js's new bundler, with webpack loader support, custom resolution, and performance optimizations.
Supported webpack loaders include:
- @svgr/webpack 30961 K - Convert SVG to React components
- yaml-loader 552 K - Load YAML files as JSON
- raw-loader 3643 K - Import files as strings
- sass-loader 14750 K - Process Sass files
- babel-loader 19722 K - Transform JavaScript
- svg-inline-loader 221 K - inlines SVG as module
- string-replace-loader 292 K - perform replacements (plain and regular expression) in the contents
Next.js automatically detects your project's root by looking for common lockfiles (e.g., pnpm-lock.yaml, package-lock.json, yarn.lock, bun.lock, bun.lockb etc.). If your structure differs, you can manually define the root using the root option.
const path = require('path')
module.exports = {
turbopack: {
// Set custom root for monorepos
root: path.join(__dirname, '../..'),
// Configure loaders
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
'*.md': {
loaders: ['raw-loader'],
as: '*.js',
},
},
// Set up aliases
resolveAlias: {
'@': './src',
styles: './src/styles',
public: './public',
underscore: 'lodash',
mocha: { browser: 'mocha/browser-entry.js' }, // conditional export: aliased to mocha/browser-entry.js
},
// Custom extensions
resolveExtensions: ['.mdx', '.tsx', '.ts', '.jsx', '.js', '.json'], // overwrites the original resolve extensions
},
}
Turbopack supports many existing webpack loaders, but with limitations: only a core part of the loader API is implemented, only JavaScript-returning loaders are supported (not for styles or images), and loader options must use plain JavaScript values. Loaders are configured in next.config.js by mapping file extensions to loader lists.
Turbopack for Next.js includes built-in support for CSS and modern JavaScript compilation, eliminating the need for custom loader configurations like css-loader, postcss-loader, or babel-loader when using @babel/preset-env.
9. typescript
The typescript configuration controls how Next.js handles TypeScript during builds. By default, Next.js fails production builds when TypeScript errors are present.
module.exports = {
typescript: {
// !! WARN !!
// Dangerously allow production builds to successfully complete even if
// your project has type errors.
// !! WARN !!
ignoreBuildErrors: true,
},
}
When to consider using ignoreBuildErrors:
- Emergency deployments with non-critical type errors
- Gradual TypeScript adoption in large codebases
- External type checking in CI/CD pipelines
- Development environments where type checking happens separately
Better alternatives to disabling type checking:
// Use TypeScript's error suppression for specific issues
// @ts-ignore
const problematicCode = someUntypedLibrary()
// Use type assertions for complex scenarios
const data = response as MyExpectedType
// Configure tsconfig.json for gradual adoption
{
"compilerOptions": {
"strict": false, // Start with loose checking
"noImplicitAny": false, // Allow implicit any temporarily
"skipLibCheck": true // Skip checking node_modules
},
"exclude": ["legacy-code/**/*"] // Exclude problematic directories
}
Best Practice: Instead of disabling TypeScript errors globally, fix them incrementally or use TypeScript's built-in suppression mechanisms for specific cases.
10. webpack
The webpack function allows you to extend Next.js's webpack configuration for custom loaders, plugins, and build optimizations.
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, nextRuntime, webpack }) => {
// Add custom rules
config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack']
})
// Add plugins
config.plugins.push(
new webpack.DefinePlugin({
__BUILD_ID__: JSON.stringify(buildId),
__IS_SERVER__: isServer,
})
)
// Modify resolve aliases
config.resolve.alias = {
...config.resolve.alias,
'@': path.resolve(__dirname, 'src'),
}
return config
},
}
The webpack function receives a context object with:
- buildId - Unique identifier for the build
- dev - Boolean indicating development mode
- isServer - Boolean indicating server-side compilation
- nextRuntime - Target runtime ("edge", "nodejs", or undefined)
- defaultLoaders - Next.js's built-in loaders
Common webpack customizations:
// Adding MDX support
config.module.rules.push({
test: /\.mdx?$/,
use: [
defaultLoaders.babel,
{
loader: '@mdx-js/loader',
options: { /* mdx options */ }
}
]
})
// Bundle analyzer for optimization
if (!dev && !isServer) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer')
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
})
)
}
// Ignore unnecessary files
config.plugins.push(
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
})
)
The function executes three times during build:
- Once for client-side compilation
- Once for server-side compilation (Node.js runtime)
- Once for edge runtime compilation (if using edge features)
Related plugins:
- @next/mdx 132316 : Use MDX 18506 with Next.js.
- @next/bundle-analyzer 132316 : Visualize the size and content of your Webpack bundles.
Next.js supports CSS and SCSS out of the box. Do not include their plugins in your webpack configurations.