Initializing Enclave...

How to Fix 'Module not found: Can't resolve @emotion/react' in MUI v5

Threat/Impact Level: HIGH | Downtime Risk: HIGH | Time to Fix: 5 mins


TL;DR

  • What broke: MUI v5 replaced JSS with Emotion as its styling engine. @emotion/react and @emotion/styled are required peer dependencies — they are not auto-installed with @mui/material.
  • How to fix it: Run npm install @emotion/react @emotion/styled and verify versions are compatible with your @mui/material version.
  • Fast path: Use our Client-Side Sandbox above to drop your package.json and auto-refactor the dependency block instantly.

The Incident (What Does the Error Mean?)

Your build output looks exactly like this:

Module not found: Can't resolve '@emotion/react'
  > 1 | import { styled } from '@mui/material/styles';

ERROR in ./src/App.tsx
Module not found: Error: Can't resolve '@emotion/react' in '/app/node_modules/@mui/styled-engine'

Immediate consequence: Webpack/Vite halts compilation entirely. Zero components render. Your app is dead on arrival — local dev, staging, and any CI pipeline building the frontend all fail simultaneously.


The Attack Vector / Blast Radius

This is a silent peer dependency trap. npm install @mui/material succeeds with exit code 0 and zero warnings if you're on npm v7+ with --legacy-peer-deps or a loose .npmrc. Your node_modules looks populated. The error only surfaces at build time, not install time.

Cascading failure risk:

  • CI/CD pipelines fail at the build step, blocking all deploys.
  • If your Dockerfile caches the npm install layer but not the build layer, you burn 10+ minutes per pipeline run before hitting the error.
  • Teams using npm ci in strict mode may see this masked until a fresh environment spins up — making it a "works on my machine" incident.
  • Monorepos with hoisted dependencies can have one package silently satisfying the peer dep for another, making the failure environment-specific and non-deterministic.

How to Fix It

Basic Fix

Install the missing peer dependencies explicitly:

npm install @emotion/react @emotion/styled

or with Yarn:

yarn add @emotion/react @emotion/styled

Enterprise Best Practice

Pin exact compatible versions aligned to your @mui/material version. For MUI v5.x, the required range is @emotion/react ^11 and @emotion/styled ^11. Lock them in package.json explicitly — do not rely on peer dep resolution.

  "dependencies": {
-   "@mui/material": "^5.14.0"
+   "@mui/material": "^5.14.0",
+   "@emotion/react": "^11.11.1",
+   "@emotion/styled": "^11.11.0"
  }

If you're using MUI's date pickers or lab components, also add:

  "dependencies": {
    "@mui/material": "^5.14.0",
    "@emotion/react": "^11.11.1",
-   "@emotion/styled": "^11.11.0"
+   "@emotion/styled": "^11.11.0",
+   "@mui/x-date-pickers": "^6.0.0"
  }

If you are using styled-components instead of Emotion (valid alternative), install the MUI styled-components engine:

- "@emotion/react": "^11.11.1",
- "@emotion/styled": "^11.11.0",
+ "@mui/styled-engine-sc": "^5.14.0",
+ "styled-components": "^5.3.0"

And add a Webpack/Vite alias:

// vite.config.ts
  resolve: {
    alias: {
+     '@mui/styled-engine': '@mui/styled-engine-sc'
    }
  }

💡 Tired of pasting proprietary configs into ChatGPT? Generic AI tools log your company's ARNs, DB strings, and private keys. StackEngine is a zero-backend, pure Client-Side WASM utility. Drop your failing config into the sandbox above. We redact your secrets locally in the browser and auto-generate the refactored code using your own API key.


Prevention in CI/CD

1. Enforce peer dependency validation in your pipeline.

Add npm ls @emotion/react @emotion/styled as a preflight check:

# .github/workflows/build.yml
- name: Validate MUI peer deps
  run: |
    npm ls @emotion/react || (echo "MISSING: @emotion/react" && exit 1)
    npm ls @emotion/styled || (echo "MISSING: @emotion/styled" && exit 1)

2. Use publint or are-the-types-wrong in your package validation step to catch peer dep mismatches before they reach build.

3. Add a Renovate or Dependabot grouping rule to keep @mui/* and @emotion/* bumped together:

// renovate.json
{
  "packageRules": [
    {
      "matchPackagePrefixes": ["@mui/", "@emotion/"],
      "groupName": "MUI + Emotion"
    }
  ]
}

4. Commit a package-lock.json or yarn.lock. Never run installs without a lockfile in CI. Use npm ci — not npm install — in all pipeline stages to guarantee reproducible dependency trees.

5. Add an .npmrc guard in the repo root to prevent silent peer dep skipping:

legacy-peer-deps=false
strict-peer-deps=true

This forces npm to error loudly on peer dep conflicts instead of silently resolving them incorrectly.

Related Diagnostics

"Part of the Syntax Utility Matrix."

View all 153 Syntax Tools →