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:

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:

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:



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:

This is particularly beneficial for:

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:

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:

However, there are important considerations:

Best practices for production source maps:



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:

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:
Benefits of Turbopack:
Current Limitations:

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:

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:

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:

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:

Related plugins:

Next.js supports CSS and SCSS out of the box. Do not include their plugins in your webpack configurations.