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/reactand@emotion/styledare required peer dependencies — they are not auto-installed with@mui/material. - How to fix it: Run
npm install @emotion/react @emotion/styledand verify versions are compatible with your@mui/materialversion. - Fast path: Use our Client-Side Sandbox above to drop your
package.jsonand 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 installlayer but not the build layer, you burn 10+ minutes per pipeline run before hitting the error. - Teams using
npm ciin 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.