DEV Community

Cover image for How to Fix “Unable to Resolve Module” Errors in React Native and Expo
Asta Silva
Asta Silva

Posted on

How to Fix “Unable to Resolve Module” Errors in React Native and Expo

How to Fix “Unable to Resolve Module” Errors in React Native and Expo

If you have been working with React Native or Expo for a while, there is a good chance you have seen an error that looks something like this:

Unable to resolve module ./components/Header from App.js

None of these files exist:
  * components/Header(.native|.ios|.android|.js|.jsx|.ts|.tsx)
  * components/Header/index(.native|.ios|.android|.js|.jsx|.ts|.tsx)
Enter fullscreen mode Exit fullscreen mode

Or maybe:

Unable to resolve module react-native-safe-area-context from App.js
Enter fullscreen mode Exit fullscreen mode

Or the error is buried somewhere inside a much larger Metro bundler log, making it harder to see what is actually wrong.

The annoying part about this error is that "Unable to resolve module" does not always mean the same thing.

Sometimes the file path is wrong. Sometimes the package was never installed. Sometimes it is installed, but your dependencies are in a bad state. And sometimes everything looks correct until you notice that one letter in a filename has the wrong capitalization.

I've run into all of these before.

So instead of randomly deleting node_modules and hoping for the best, here is how I usually work through this error.


First, read the exact module Metro cannot find

This sounds obvious, but the first line of the error usually tells you exactly what Metro is looking for.

For example:

Unable to resolve module ./components/Header from App.js
Enter fullscreen mode Exit fullscreen mode

Metro is trying to find:

./components/Header
Enter fullscreen mode Exit fullscreen mode

relative to:

App.js
Enter fullscreen mode Exit fullscreen mode

That immediately gives you something to check.

Ask yourself:

  • Does that file actually exist?
  • Is the path correct?
  • Is the filename spelled correctly?
  • Are you importing it from the correct folder?

For example, imagine your project looks like this:

my-app/
├── App.js
└── components/
    └── Header.js
Enter fullscreen mode Exit fullscreen mode

Then this import should work:

import Header from "./components/Header";
Enter fullscreen mode Exit fullscreen mode

But this will not:

import Header from "./component/Header";
Enter fullscreen mode Exit fullscreen mode

One missing s is enough to break the build.

When the error points to a local file, I usually start here before doing anything else.


Check the file name and capitalization

This one can be surprisingly annoying, especially if your app worked on one machine but suddenly fails during a build or after pushing the project somewhere else.

Imagine your file is named:

header.js
Enter fullscreen mode Exit fullscreen mode

But your import says:

import Header from "./components/Header";
Enter fullscreen mode Exit fullscreen mode

Depending on the operating system and environment, this can cause problems because:

header.js
Enter fullscreen mode Exit fullscreen mode

and:

Header.js
Enter fullscreen mode Exit fullscreen mode

are not always treated as the same file.

The same thing can happen with folders:

Components/
Enter fullscreen mode Exit fullscreen mode

vs:

components/
Enter fullscreen mode Exit fullscreen mode

If Metro says it cannot find a local module and the path looks correct at first glance, check every part of the path carefully.

I have lost more time than I would like to admit because of a single capital letter.


Make sure the package is actually installed

Sometimes the missing module is not one of your own files.

For example:

Unable to resolve module react-native-safe-area-context
Enter fullscreen mode Exit fullscreen mode

In that case, check whether the package exists in your project.

You can look inside package.json and see whether it is listed under dependencies.

For an Expo project, it is usually better to install Expo-compatible packages with:

npx expo install react-native-safe-area-context
Enter fullscreen mode Exit fullscreen mode

For a regular React Native project, you would normally use:

npm install react-native-safe-area-context
Enter fullscreen mode Exit fullscreen mode

or:

yarn add react-native-safe-area-context
Enter fullscreen mode Exit fullscreen mode

The exact command depends on your project, but the important part is this:

Do not assume a package is installed just because you used it in your code.

It is also possible that you copied code from another project, tutorial, or GitHub repository without installing all of the required dependencies.


Check if the package name is correct

Another simple but common problem is importing the wrong package name.

For example, you might write something like:

import Something from "react-native-something";
Enter fullscreen mode Exit fullscreen mode

but the actual package name could be slightly different.

Before reinstalling everything, check:

  1. The package name in your import.
  2. The package name in package.json.
  3. The package name from the package documentation.

One small typo can produce the same "Unable to resolve module" error as a completely missing dependency.


Reset the Metro cache

If the file or package exists and the import looks correct, the next thing I would try is clearing Metro's cache.

For Expo:

npx expo start -c
Enter fullscreen mode Exit fullscreen mode

For React Native, you can try:

npx react-native start --reset-cache
Enter fullscreen mode Exit fullscreen mode

Metro caches information to make development faster, but occasionally the cache gets in the way after things change.

For example, you might have:

  • renamed a file,
  • moved a folder,
  • installed a new package,
  • changed an import,
  • switched branches in Git.

If the project is still behaving like the old version exists, clearing the cache is a quick thing to try.

I would not start by deleting half the project, though. Resetting the cache is much less destructive.


Check your node_modules

Sometimes the dependency is listed in package.json, but something went wrong during installation.

This can happen after:

  • switching branches,
  • changing package versions,
  • interrupting an installation,
  • moving the project to another computer,
  • or getting dependency conflicts.

A common approach is to reinstall your dependencies.

First, remove node_modules.

Then run:

npm install
Enter fullscreen mode Exit fullscreen mode

Or, if you use Yarn:

yarn install
Enter fullscreen mode Exit fullscreen mode

After that, start the project again and clear Metro's cache.

For Expo, that could look like:

npx expo start -c
Enter fullscreen mode Exit fullscreen mode

Try to use the same package manager consistently. If your project uses package-lock.json, randomly switching between npm, Yarn, and other package managers can create confusing dependency problems.


Check whether you are importing from the correct location

This is especially easy to miss after moving files around.

Imagine you originally had:

src/
├── screens/
│   └── HomeScreen.js
└── components/
    └── Header.js
Enter fullscreen mode Exit fullscreen mode

Inside HomeScreen.js, you might import:

import Header from "../components/Header";
Enter fullscreen mode Exit fullscreen mode

Then later, you move HomeScreen.js somewhere else:

src/
├── app/
│   └── screens/
│       └── HomeScreen.js
└── components/
    └── Header.js
Enter fullscreen mode Exit fullscreen mode

The old import path may no longer be correct.

You would need to update it accordingly:

import Header from "../../components/Header";
Enter fullscreen mode Exit fullscreen mode

When you see an "Unable to resolve module" error after reorganizing your project, check whether the import path still matches the new folder structure.


Be careful with relative paths

Relative imports can become difficult to read when your project grows.

You might end up with something like:

import Something from "../../../../components/Something";
Enter fullscreen mode Exit fullscreen mode

At that point, it becomes much easier to accidentally use one ../ too many or too few.

If the error points to a long relative path, carefully trace it from the file where the import is written.

For example:

import Header from "../../../components/Header";
Enter fullscreen mode Exit fullscreen mode

Do not just count the dots and slashes quickly. Actually check the location of the current file and follow the path step by step.

It is boring, but it is often faster than trying random fixes.


Check whether the package is compatible with Expo

This is more important if you are using Expo.

You may find a React Native package online, install it successfully, and then run into problems because the version does not match your Expo SDK or the package needs native setup that your project does not currently support.

When possible, use:

npx expo install package-name
Enter fullscreen mode Exit fullscreen mode

instead of blindly installing the latest version with npm.

Expo can choose a version that is compatible with your current SDK.

You can also run:

npx expo-doctor
Enter fullscreen mode Exit fullscreen mode

to check your project for dependency and configuration issues.

If Metro suddenly cannot resolve something after installing or updating a package, compatibility is worth checking.


Watch out for renamed or removed files

Another situation that can cause this error is when your code still imports something that no longer exists.

For example, you rename:

OldButton.js
Enter fullscreen mode Exit fullscreen mode

to:

CustomButton.js
Enter fullscreen mode Exit fullscreen mode

but somewhere in the project, you still have:

import OldButton from "./OldButton";
Enter fullscreen mode Exit fullscreen mode

The error might not happen immediately if that file is not loaded until you visit a specific screen.

This is why I would search the project for the old filename.

Your editor's global search is useful here. Search for:

OldButton
Enter fullscreen mode Exit fullscreen mode

and see whether any old imports are still left behind.


Check index files

Sometimes the missing module is actually caused by an index.js or index.ts file.

For example:

components/
├── Button/
│   ├── Button.js
│   └── index.js
Enter fullscreen mode Exit fullscreen mode

You might import it like this:

import Button from "./components/Button";
Enter fullscreen mode Exit fullscreen mode

That usually depends on Metro being able to resolve the folder's index file correctly.

If index.js was deleted, renamed, or contains a broken export, your import setup may stop working.

Check whether the folder contains the file Metro expects.

For example:

export { default } from "./Button";
Enter fullscreen mode Exit fullscreen mode

Or:

export { Button } from "./Button";
Enter fullscreen mode Exit fullscreen mode

The correct setup depends on whether you are using default or named exports.

The important part is to check the whole import chain, not just the first file.


Default exports and named exports are a different problem, but still worth checking

This usually causes a different error, but it can easily appear around the same time.

For example, this is a default export:

export default Header;
Enter fullscreen mode Exit fullscreen mode

And it is imported like this:

import Header from "./Header";
Enter fullscreen mode Exit fullscreen mode

A named export looks like this:

export const Header = () => {
  return null;
};
Enter fullscreen mode Exit fullscreen mode

And it should be imported like this:

import { Header } from "./Header";
Enter fullscreen mode Exit fullscreen mode

If you have already fixed the module resolution error but the app still fails afterward, this is one of the next things I would check.

Sometimes you fix one problem and Metro finally gets far enough to show you the next one.

That is just part of debugging.


Monorepos can make module resolution more complicated

If you are using a monorepo, workspaces, shared packages, or code outside the main app folder, Metro module resolution can become more complicated.

Your project might look something like this:

my-project/
├── apps/
│   └── mobile/
└── packages/
    └── shared/
Enter fullscreen mode Exit fullscreen mode

Then the React Native or Expo app might need to import code from:

packages/shared
Enter fullscreen mode Exit fullscreen mode

In these cases, a normal relative import may not be enough. Metro may need additional configuration to watch or resolve files outside the main project directory.

If you only started seeing the error after introducing a workspace or shared package, I would focus on your Metro configuration instead of repeatedly reinstalling dependencies.

Monorepo issues usually need a more specific fix because the correct setup depends heavily on how the project is structured.


If you use Expo Router, check your imports and project structure

Expo Router adds another layer to how files are organized.

For example, your routes may live inside:

app/
Enter fullscreen mode Exit fullscreen mode

and you may have layouts, route groups, and nested folders.

If you recently moved or renamed route files, double-check your imports and references.

Also make sure the required Expo Router packages are correctly installed for your current Expo setup.

When something goes wrong inside a routing setup, the error message may make it look like a general Metro problem when the real issue is simply an incorrect import somewhere inside a route or layout.

Again, start with the exact module Metro says it cannot find.


Do not immediately delete everything

When developers hit a module resolution error, a common reaction is to do all of this at once:

Delete node_modules
Delete package-lock.json
Clear Metro
Clear npm cache
Reinstall everything
Restart the computer
Enter fullscreen mode Exit fullscreen mode

Sometimes that works.

But it can also make debugging harder because now you have changed five different things and do not know what actually fixed the problem.

I would usually check the error in this order:

  1. Read the exact missing module.
  2. Check whether the file or package exists.
  3. Check the spelling and capitalization.
  4. Check the import path.
  5. Check whether the dependency is installed.
  6. Clear the Metro cache.
  7. Reinstall dependencies if necessary.
  8. Check Expo or React Native version compatibility.
  9. Investigate Metro configuration for more complex project setups.

This is usually much faster than throwing random commands at the project.


A quick example

Imagine you get this error:

Unable to resolve module ./components/ProfileCard from App.js
Enter fullscreen mode Exit fullscreen mode

You check your project and see:

components/
└── Profilecard.js
Enter fullscreen mode Exit fullscreen mode

The problem is the capitalization.

Your import says:

import ProfileCard from "./components/ProfileCard";
Enter fullscreen mode Exit fullscreen mode

But the actual file is:

Profilecard.js
Enter fullscreen mode Exit fullscreen mode

Rename the file so it matches:

ProfileCard.js
Enter fullscreen mode Exit fullscreen mode

Then restart Metro if necessary:

npx expo start -c
Enter fullscreen mode Exit fullscreen mode

That is a simple example, but it shows why reading the exact error matters.

The error is not always asking you to reinstall your entire project. Sometimes Metro is simply telling you that it cannot find something because the path does not exactly match what exists on disk.


Final thoughts

"Unable to resolve module" errors can look more serious than they really are.

Most of the time, the problem comes down to one of these things:

  • A wrong import path
  • A missing package
  • A typo in the package name
  • A filename capitalization problem
  • A stale Metro cache
  • Broken or missing dependencies
  • A file that was moved or renamed
  • A more complex Metro configuration issue

The biggest thing I have learned is to start with the exact module Metro says it cannot find.

Do not start by reinstalling the entire project.

Check what Metro is looking for, where it is looking from, and whether that file or package actually exists. In many cases, the answer is much simpler than the size of the error message makes it seem.

If your error is much messier than this—especially if the missing module is buried inside a large Expo, Metro, dependency, or build error—you can also paste the full error into FixMyError and get help breaking down what is actually causing it.

Sometimes the hard part is not finding a fix. It is figuring out which part of a long error log actually matters.

Try it here: https://www.fixmyerrorapp.com

Top comments (0)