How to Fix the npm ERESOLVE Dependency Error in Expo
Hitting npm ERESOLVE in an Expo project means a peer dependency conflict. The reliable fix is to let Expo choose SDK-compatible versions, not to force-install past it.
TL;DR
The npm ERESOLVE error means npm cannot satisfy a package's peerDependencies, a tree check it has enforced since npm 7. In an Expo project the fix is almost always to install with npx expo install, or run npx expo install --fix, so Expo picks versions that match your installed SDK instead of letting npm guess. Reach for --legacy-peer-deps or --force only as a deliberate, temporary escape hatch, then pin your SDK and React versions so it stays fixed. Start the app's screens from a free VP0 design and let Claude Code or Cursor wire them.
If npm throws an ERESOLVE error in an Expo project, it is telling you it cannot satisfy a package’s peer dependencies, and the reliable fix is to let Expo choose versions that match your SDK rather than forcing npm past the conflict. Run npx expo install <package> instead of npm install <package>, or run npx expo install --fix to realign everything to your SDK in one pass. The screens around the dependency you are adding are fastest to start from a free VP0 design that Claude Code or Cursor reads directly, so your time goes to the fix and not the layout.
What the ERESOLVE error is actually telling you
ERESOLVE is short for “could not resolve dependency tree.” npm prints it when it tries to build a single tree where every package’s declared peerDependencies are satisfied, and finds that two requirements contradict each other. A common shape is a library that lists React 18 as a peer while your project has resolved React 19, so there is no version of React that makes both happy.
This check is not new behavior in your project; it is new behavior in npm. Since npm 7 the CLI installs and validates peer dependencies automatically, where npm 6 silently ignored them. That single change is why a project that installed cleanly a couple of years ago now stops with a wall of red text. The official npm install documentation describes the same flags people reach for, --legacy-peer-deps and --force, and is the right reference when you decide how to respond.
Why Expo projects hit it so often
Expo is opinionated about versions on purpose. Each Expo SDK pins a matched set of packages, React, React Native, and the Expo libraries, so they are tested together as a unit. The moment you run npm install some-library@latest, npm fetches whatever the newest version declares, which was very likely built against a different React Native than your SDK pins, and the peer requirements collide.
The Expo guide to installing libraries is explicit that you should install with npx expo install rather than the raw npm command for exactly this reason: Expo looks up the version of each package that is known to work with your installed SDK and installs that, instead of the latest on the registry. If you have ever fixed a tracking or payments screen, the Expo Stripe integration walkthrough follows the same install-the-pinned-version discipline.
The fix that holds: let Expo pick the versions
For a single new package, install it the Expo way:
npx expo install react-native-reanimated
When the tree is already broken, realign the whole project to your SDK in one command:
npx expo install --fix
--fix walks every Expo-managed dependency, compares the installed version against the version your SDK expects, and corrects the mismatches. After it runs, delete node_modules and your lockfile and reinstall so the tree is rebuilt from the corrected versions:
rm -rf node_modules package-lock.json
npx expo install --fix
This resolves the conflict properly, which is the difference between fixing ERESOLVE and merely hiding it.
When —legacy-peer-deps or —force is the right call
Sometimes the conflicting package is not Expo-managed, for example a pure JavaScript utility that simply declares an old peer range. There Expo cannot pick a version for you, and an override is reasonable, as long as it is deliberate.
| Approach | What it does | Use it when |
|---|---|---|
| npx expo install —fix | Sets Expo packages to SDK-correct versions | The conflict involves React, React Native, or an Expo library |
| npm install —legacy-peer-deps | Ignores peer conflicts, installs anyway (npm 6 behavior) | A non-Expo package declares an outdated peer range |
| npm install —force | Ignores peers and overwrites cache and mismatches | Last resort, when you accept and have tested the mismatch |
Prefer --legacy-peer-deps over --force: it is the narrower hammer, silencing only the peer check, while --force overrides far more and hides problems you will meet later. Neither one repairs the mismatch, so log why you used it.
Keeping it from coming back
The durable fix is to stop fighting npm’s resolver. Always add packages with npx expo install, commit your lockfile so teammates resolve the same tree, and run npx expo-doctor before a release to catch version drift early. When you upgrade, change the SDK first with npx expo install expo@latest and let --fix pull the rest into line, rather than bumping individual packages by hand. A clean starting point helps too: the best Expo boilerplate choices for 2026 already ship with a coherent, SDK-aligned set of versions. If an AI builder generated your project and left mismatched versions, the fix for Expo Router export errors from Bolt covers the same realign-to-the-SDK move.
What to choose
When ERESOLVE stops an Expo install, do not start with --force. Install the Expo way with npx expo install, and when the tree is already tangled run npx expo install --fix, then wipe node_modules and the lockfile and reinstall. Keep --legacy-peer-deps for the narrow case of a non-Expo package with a stale peer range, and avoid --force unless you have tested the mismatch and accept it. Pin versions through the SDK, commit your lockfile, and run expo-doctor so the error does not return. For the UI itself, start the screens from a free, $0 VP0 design and let Claude Code or Cursor build them while you keep the dependency tree clean.
Frequently asked questions
How do I fix the npm ERESOLVE error in an Expo project?
Install with npx expo install
What does ERESOLVE could not resolve mean?
It means npm built a dependency tree where a package’s declared peerDependencies cannot all be satisfied at once, for example a library that needs React 18 while your project resolves React 19. npm has enforced this check since version 7, which is why projects that installed cleanly on npm 6 suddenly fail. The error is npm protecting you from a mismatched tree, not a bug in your code.
Should I use —force or —legacy-peer-deps?
Prefer —legacy-peer-deps, which tells npm to ignore peer conflicts and install anyway, mirroring npm 6 behavior. —force is broader and will also overwrite cache and pull in deliberately mismatched versions, so it hides more problems. Neither fixes the underlying mismatch; they only silence the check. In Expo, reach for npx expo install —fix first, since it resolves the conflict properly instead of ignoring it.
Why does Expo throw dependency errors more than plain React Native?
Expo ships an SDK that pins a matched set of packages, including React and React Native, to each SDK version. When you install a library version built for a different SDK, its peer requirements clash with the pinned set and npm raises ERESOLVE. That is also why npx expo install exists: it looks up the version of each package that is known to work with your SDK and installs that instead of the latest on npm.
Can VP0 help me build the app while I sort out dependencies?
Yes. VP0 is a free iOS design library where each screen has an AI-readable source page, so you copy a link and Claude Code or Cursor builds the real screen in React Native or SwiftUI. That keeps your UI work moving while you resolve the dependency tree, and because you own the generated code, there is no extra runtime dependency added to the conflict you are already untangling.
More questions from VP0 vibe coders
How do I fix the npm ERESOLVE error in an Expo project?
Install with npx expo install <package> instead of npm install <package>, so Expo picks a version that matches your SDK. If your tree is already broken, run npx expo install --fix to realign every Expo-managed package in one pass, then reinstall. Only fall back to npm install --legacy-peer-deps if a non-Expo package still conflicts, and treat that as temporary. Start the screens from a free VP0 design and let Claude Code or Cursor build them while you handle the dependency.
What does ERESOLVE could not resolve mean?
It means npm built a dependency tree where a package's declared peerDependencies cannot all be satisfied at once, for example a library that needs React 18 while your project resolves React 19. npm has enforced this check since version 7, which is why projects that installed cleanly on npm 6 suddenly fail. The error is npm protecting you from a mismatched tree, not a bug in your code.
Should I use --force or --legacy-peer-deps?
Prefer --legacy-peer-deps, which tells npm to ignore peer conflicts and install anyway, mirroring npm 6 behavior. --force is broader and will also overwrite cache and pull in deliberately mismatched versions, so it hides more problems. Neither fixes the underlying mismatch; they only silence the check. In Expo, reach for npx expo install --fix first, since it resolves the conflict properly instead of ignoring it.
Why does Expo throw dependency errors more than plain React Native?
Expo ships an SDK that pins a matched set of packages, including React and React Native, to each SDK version. When you install a library version built for a different SDK, its peer requirements clash with the pinned set and npm raises ERESOLVE. That is also why npx expo install exists: it looks up the version of each package that is known to work with your SDK and installs that instead of the latest on npm.
Can VP0 help me build the app while I sort out dependencies?
Yes. VP0 is a free iOS design library where each screen has an AI-readable source page, so you copy a link and Claude Code or Cursor builds the real screen in React Native or SwiftUI. That keeps your UI work moving while you resolve the dependency tree, and because you own the generated code, there is no extra runtime dependency added to the conflict you are already untangling.
Part of the React Native & Expo: Mobile Frontend Architecture hub. Browse all VP0 topics →
Keep reading
Blank White Screen on Launch in AI-Built Expo Apps? Fix
AI-generated Expo app launching to a blank white screen? It is a JS-load, render, or splash-timing issue. Here are the causes and the fixes.
v0 by Vercel mobile app export: from web to a real iOS app
v0 by Vercel generates web React, so there is no direct mobile export. Here are the three real paths from a v0 design to an iOS app, and when each fits.
An Offline-First Folder Architecture for Expo Apps
An offline-first Expo app needs a clear data, sync, and UI split. Here is a folder architecture that keeps offline working and an AI agent on track while it builds.
Untangle a FlutterFlow Export and Run the Bare Source
A FlutterFlow export is a complete Flutter project, not React Native. Here is how to open it in an IDE, add your own Firebase, and run the bare source cleanly.
How to Clean Up and Format FlutterFlow and Lovable Exports
Exported builder code works but reads machine-made. Here is the cleanup ladder for FlutterFlow and Lovable exports: format, lint, structure, ownership.
React Native Agency for Startups in India: How to Choose
The code is the cheapest part of what an agency sells. Here is how startups vet React Native agencies in India: shipped apps, discovery sprints, small contracts.