Fix barrel_optimize Build Warnings with MUI in Next.js

Why next build floods the terminal with __barrel_optimize__ warnings on @mui/material, when they are safe to ignore, and the three ways to stop them.

Mahdi Ben RhoumaMahdi Ben Rhouma · Updated

Run next build on a project that uses @mui/material and, on some Next.js versions, the terminal fills with warnings shaped like this:

plaintext
The requested module '__barrel_optimize__?names=useTheme&wildcard!=!./styles'
contains conflicting star exports for the name '__esModule' with the previous
requested module '__barrel_optimize__?names=useTheme&wildcard!=!./utils'

Should you care? Usually not. The build completes, the output works, and the warning is noise from Next.js rewriting your MUI imports behind the scenes — the pattern reported in vercel/next.js #55663 built and ran fine. But "usually" is doing some work in that sentence: the same machinery has shipped versions where the optimisation silently stopped working and the whole of @mui/material landed in the client bundle. So the right move is to understand what the warning is, check your bundle once, and then silence it deliberately.

The mechanism: barrel files and what Next.js does to them#

@mui/material's root index.js is a barrel file — a module whose only job is to re-export hundreds of others so you can write:

tsx
import { Box, Button, useTheme } from '@mui/material';

Convenient, but expensive. Resolving that one import means resolving everything the barrel re-exports, which slows both next dev and next build, and — with bundlers that cannot fully tree-shake the package — can drag unused components into your bundle.

Next.js addresses this with optimizePackageImports: at build time it rewrites the barrel import into direct per-module imports, "only load[ing] the modules you are actually using, while still giving you the convenience of writing import statements with many named exports". The docs list the packages optimised by default — @mui/material and @mui/icons-material are both on it, alongside lucide-react, date-fns, antd and others. The feature still sits under the experimental key.

The __barrel_optimize__?names=... string in the warning is that rewrite made visible: it is the internal loader Next.js generates for each barrel it transforms. The "conflicting star exports for __esModule" complaint happens when two rewritten modules both re-export the same synthetic __esModule marker — an artefact of how MUI structures its wildcard exports, not of your code. The warnings arrived with the barrel optimiser itself in Next.js 13.5 (issue #55663 was filed against 13.5.2-canary.1 and later closed).

Silence it properly — options from cleanest to bluntest#

1. Import from the component path directly#

MUI's own bundle-size guidance recommends first-level path imports:

tsx
import Box from '@mui/material/Box';
import Button from '@mui/material/Button';
import { useTheme } from '@mui/material/styles';

No barrel, nothing to rewrite, no warning — and the fastest dev-server resolve times of any option. The cost is more import lines, which your editor's auto-import handles anyway. This is the option we use in the patterns shown in our Next.js performance guide.

2. Pin the optimiser's behaviour explicitly#

If you prefer keeping named imports, declare the package yourself instead of relying on the default list — explicit config survives default-list changes between versions:

js
// next.config.js
module.exports = {
  experimental: {
    optimizePackageImports: ['@mui/material', '@mui/icons-material'],
  },
};

The warnings may remain on affected versions, but the rewrite is guaranteed on, which is what actually matters for your bundle.

3. Upgrade Next.js#

The noisy-warning phase clusters around Next.js 13.5–14.x. The original issue is closed, and current majors do not emit the __esModule conflict for standard @mui/material imports. If you are stuck on an affected version for other reasons, treat the warning as cosmetic — after the one check below.

When the warning is hiding a real problem#

Two failure modes reported against the same machinery deserve a check rather than a shrug:

  • The optimisation silently off. Issue #57624 reported that on early Next.js 14 releases optimizePackageImports stopped working and the entire @mui/material package shipped to the client despite being on the default list. Warnings absent ≠ bundle healthy.
  • Turbopack gaps. Issue #75131 (January 2025) reported barrel optimisation not applying to @mui/joy under --turbopack, and #75148 the same for local workspace packages. If you build with Turbopack, do not assume parity with the webpack path — the two bundlers resolve differently, as we saw from the other side in the Turbopack stuck-build investigation.

The check is one command:

bash
ANALYZE=true next build   # with @next/bundle-analyzer wired in next.config.js

Open the client-bundle report and look for @mui/material as a single large block. Seeing individual small modules (Box, Button, …) means the rewrite works and the warnings are cosmetic. Seeing the whole package means you are in the #57624 case: switch to direct path imports (option 1), which fixes the bundle regardless of what the optimiser does.

Upstream status#

As of our last check (August 2026): #55663 is closed; the optimizePackageImports API remains documented as experimental with @mui/material on the default list; the Turbopack-specific gaps (#75131, #75148) were filed in 2025 against the newer bundler path. If your exact warning text differs from the __esModule conflict above, search it verbatim in the vercel/next.js issue tracker — the barrel optimiser produces several distinct messages, and build errors that merely mention a module path can have unrelated causes, as with the next/babel parsing error or ChunkLoadError failures at runtime.

Enforcing direct imports with an ESLint rule#

Fixing existing imports (option 1 above) stops the warning today, but nothing prevents the next contributor from typing import { Button } from '@mui/material' again next week. ESLint's built-in no-restricted-imports rule can turn that into a build-time error instead of a warning nobody reads:

js
// eslint.config.mjs
export default [
  {
    rules: {
      'no-restricted-imports': ['error', {
        paths: [
          {
            name: '@mui/material',
            message: 'Import the component path directly, e.g. "@mui/material/Button" — avoids the barrel_optimize warning and keeps the bundle lean.',
          },
          {
            name: '@mui/icons-material',
            message: 'Import the icon path directly, e.g. "@mui/icons-material/Delete".',
          },
        ],
      }],
    },
  },
];

paths matches the exact bare specifier (@mui/material) and leaves subpath imports (@mui/material/Button) untouched, so the rule only fires on the pattern that produces the barrel warning in the first place. This is a plain ESLint 9 flat-config array, which matters because Next.js 16 removed the built-in next lint command entirely — teams upgrading now have to run ESLint directly and migrate any leftover .eslintrc.json to flat config themselves. If that migration hasn't happened yet, the Next.js 16 ESLint 9 flat-config migration guide covers converting the config format before this rule can even be added, including the plugins that need re-registering explicitly under flat config (they were implicit under next lint).

One caveat: this rule only catches new violations going forward. Running it against an existing codebase full of @mui/material barrel imports will fail every file at once — either fix the imports first (option 1), or scope the rule to specific directories with an ignores/files override while the rest of the codebase is migrated incrementally.

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Related fixes & guides