How to Fix: Specifying webpack configuration using node v23 in next config breaks next build

5 min read

When Node.js v23 meets Next.js webpack config, next build can fail before your application code even matters. The breakage usually comes from how the Next config file is loaded and how a custom webpack function is evaluated under newer Node module-loading behavior.

If your project builds fine until you add a custom webpack section in next.config, and the failure appears specifically on Node 23, the issue is typically not your loader rule itself. The real problem is the interaction between Next.js config loading, CommonJS vs ESM semantics, and newer Node behavior that is less forgiving when a config file mixes patterns.

Understanding the Root Cause

Next.js loads next.config.js in a very specific way during next build. A custom webpack callback such as webpack: (config) => config forces Next to evaluate that config path fully. On Node v23, projects that rely on ambiguous module format behavior can break because the config file is interpreted differently than expected.

The most common triggers are:

  • Using ES module syntax in a config file that Next expects to treat as CommonJS.
  • Using next.config.js inside a package configured with "type": "module", which changes how Node interprets .js files.
  • Importing webpack-related files or plugins in a way that works on older Node versions but fails under Node 23 resolution rules.
  • Returning or mutating webpack config with assumptions that depend on older runtime behavior.

In practice, this means a project may work until you add:

module.exports = {
  webpack: (config) => {
    return config
  },
}

That callback itself is not wrong. It simply causes Next build-time config resolution to go through code paths that expose the module-format mismatch.

The safest fix is to make your Next config format explicit and consistent. If your project is using ESM, use next.config.mjs. If your project is using CommonJS, use next.config.cjs or ensure the package is not marked as ESM for that file.

Step-by-Step Solution

The most reliable solution is to stop relying on ambiguous .js config behavior.

Option 1: Use next.config.mjs for ESM projects

If your package.json contains "type": "module", rename your config file to next.config.mjs and export it with ESM syntax.

mv next.config.js next.config.mjs

Then update the file:

/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack(config) {
    return config
  },
}

export default nextConfig

This removes ambiguity and aligns your config with how Node 23 expects ESM files to behave.

Option 2: Use next.config.cjs for CommonJS projects

If you want to keep CommonJS, rename the file to next.config.cjs and keep module.exports.

mv next.config.js next.config.cjs
/** @type {import('next').NextConfig} */
module.exports = {
  webpack(config) {
    return config
  },
}

This is especially useful if your repository includes tooling that still expects require/module.exports.

Option 3: Remove conflicting package module type

If you do not need ESM at the package level, remove the ESM declaration from package.json:

{
  "name": "your-app",
  "version": "1.0.0"
}

Then use a standard CommonJS Next config:

/** @type {import('next').NextConfig} */
module.exports = {
  webpack(config) {
    return config
  },
}

This is the least modern option, but it is simple and stable.

Verify the fix

After updating the config format, reinstall and rebuild:

rm -rf node_modules .next package-lock.json
npm install
npm run build

If the build now succeeds, the root cause was the config/module-format mismatch rather than the webpack override itself.

For modern projects, the best long-term choice is usually explicit ESM:

// next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
  webpack(config, { isServer, dev }) {
    return config
  },
}

export default nextConfig

This makes the file behavior predictable across newer Node versions.

Common Edge Cases

1. The project still fails after renaming the config file

Check for imported plugins or helper files that still mix ESM and CommonJS. For example, a config file using export default may import a helper that only works through require(), or vice versa.

2. A webpack plugin crashes only in production

Some plugins access server-only APIs or assume browser globals. Since next build creates separate client and server bundles, wrap plugin logic carefully:

const nextConfig = {
  webpack(config, { isServer }) {
    if (!isServer) {
      // client-only changes
    }
    return config
  },
}

export default nextConfig

3. The build works on Node 20 but not Node 23

That usually indicates your setup depended on older compatibility behavior. Pinning to an older Node version may unblock you temporarily, but the better fix is to make the config module format explicit.

4. Turbopack or experimental settings change the symptoms

Even if the visible error changes, the underlying issue can still be config loading. Keep your Next config minimal first, confirm it builds, then add custom webpack rules gradually.

5. Monorepo setups can hide the real package type

In a workspace, the nearest package.json with "type": "module" may affect how Node interprets files. Confirm which package boundary your Next app actually runs under.

FAQ

Why does the build only fail after adding a webpack function?

Because defining webpack() forces Next.js to fully evaluate and execute the custom config path. That exposes module-format or import-resolution problems that may stay hidden when the config is otherwise minimal.

Should I downgrade from Node 23 to fix this?

You can as a short-term workaround, but it is better to fix the config file properly. Using next.config.mjs for ESM or next.config.cjs for CommonJS is the durable solution.

Is this a webpack bug or a Next.js bug?

It is usually an integration issue triggered by how Next.js loads configuration under newer Node.js behavior. Webpack is often only the place where the error becomes visible.

If you want the most stable outcome, make the config file type explicit, avoid mixing module systems, and reintroduce custom webpack logic only after a clean next build passes. That resolves this class of Node v23 + Next.js config failures far more reliably than changing loader rules blindly.

Leave a Reply

Your email address will not be published. Required fields are marked *