Fix: React Native Metro Bundler Failed to Start or Bundle
Quick Answer
How to fix React Native Metro bundler errors — unable to resolve module, EMFILE too many open files, port already in use, transform cache errors, and Metro failing to start on iOS or Android.
The Error
When running npx react-native start or npx expo start, Metro fails with one of these errors:
error: Error: Unable to resolve module `./src/screens/Home` from `App.js`Or Metro fails to start:
Error: EMFILE: too many open files, watchOr a port conflict:
Another process is already using port 8081. Run the following command to find out which process:
lsof -i :8081Or a transform error:
error: bundling failed: Error: Unable to resolve module `crypto` from `node_modules/some-library/index.js`Or after an npm install, bundles fail silently and the simulator shows a red error screen with “Unable to load script.”
Why This Happens
Metro is React Native’s JavaScript bundler — it resolves module imports, transforms code, and serves the bundle to the simulator or device. Metro bundler failures stem from several common sources:
- Stale cache — Metro caches transform results. After dependency changes, the cache can reference modules that have moved or been removed.
- Module resolution failure — the
moduleNameMapperor Metro config does not know how to resolve a path alias, a native module, or a Node.js built-in. - File watcher limits — on Linux, the default
inotifylimit is too low for large React Native projects. - Port conflict — Metro defaults to port 8081. Another Metro instance or a different process already occupies it.
- Node.js built-in modules in web-targeted libraries — some npm packages use Node.js built-ins (
crypto,stream,fs) that do not exist in React Native’s runtime. - Corrupted
node_modules— incomplete installs or version conflicts cause Metro to fail resolving modules it expects to find.
Fix 1: Clear the Metro Cache
The most common fix for sudden Metro failures after npm install or git pull:
# Clear Metro's transform cache
npx react-native start --reset-cache
# Or for Expo
npx expo start --clear
# Full reset — clears watchman, metro cache, and node_modules cache
watchman watch-del-all
rm -rf $TMPDIR/metro-*
rm -rf $TMPDIR/react-*For a complete clean start:
# Stop Metro if running
# Clear all caches
watchman watch-del-all 2>/dev/null || true
rm -rf node_modules
rm -rf $TMPDIR/metro-*
rm -rf $TMPDIR/haste-map-*
npm install
npx react-native start --reset-cachePro Tip: Add a
cleanscript to yourpackage.jsonfor faster troubleshooting:{ "scripts": { "clean": "watchman watch-del-all && rm -rf $TMPDIR/metro-* && rm -rf node_modules && npm install", "start:clean": "npm run clean && npx react-native start --reset-cache" } }
Fix 2: Fix Unable to Resolve Module
When Metro cannot find a module you are importing:
Check the import path first:
// Wrong — relative path typo
import HomeScreen from './screens/home'; // file is HomeScreen.js, not home.js
// Correct
import HomeScreen from './screens/HomeScreen';Metro is case-sensitive even on macOS (unlike the filesystem). A file named HomeScreen.js is not resolved by ./screens/homescreen.
Add path aliases via Metro config:
// metro.config.js
const { getDefaultConfig } = require('@react-native/metro-config');
const path = require('path');
const config = getDefaultConfig(__dirname);
config.resolver.alias = {
'@components': path.resolve(__dirname, 'src/components'),
'@screens': path.resolve(__dirname, 'src/screens'),
'@utils': path.resolve(__dirname, 'src/utils'),
};
module.exports = config;Verify the module exists in node_modules:
ls node_modules/some-library/
# If empty or missing, reinstall:
npm install some-libraryFix missing peer dependencies:
npx react-native doctor
# Or
npx expo-doctorFix 3: Fix Node.js Built-in Modules Not Found
Some npm packages use Node.js built-ins (crypto, stream, buffer, path) that do not exist in React Native’s JavaScript environment:
error: bundling failed: Error: Unable to resolve module `crypto`Install polyfill packages:
npm install react-native-crypto react-native-randombytes
npm install stream-browserify readable-stream
npm install react-native-bufferConfigure Metro to use polyfills:
// metro.config.js
const { getDefaultConfig } = require('@react-native/metro-config');
const config = getDefaultConfig(__dirname);
config.resolver.extraNodeModules = {
crypto: require.resolve('react-native-crypto'),
stream: require.resolve('stream-browserify'),
buffer: require.resolve('react-native-buffer'),
path: require.resolve('path-browserify'),
os: require.resolve('react-native-os'),
};
module.exports = config;Alternative — find a React Native compatible library:
Instead of polyfilling crypto, use a React Native native module:
# Use react-native-quick-crypto instead of the crypto polyfill
npm install react-native-quick-crypto
npx pod-install # iOSFix 4: Fix EMFILE Too Many Open Files
On Linux and macOS, the file watcher limit is often too low for React Native projects with thousands of files:
Increase the inotify limit on Linux:
# Check the current limit
cat /proc/sys/fs/inotify/max_user_watches
# Increase it temporarily
sudo sysctl fs.inotify.max_user_watches=524288
# Make it permanent
echo fs.inotify.max_user_watches=524288 | sudo tee -a /etc/sysctl.conf
sudo sysctl -pOn macOS — increase file descriptor limit:
# Check current limit
ulimit -n
# Increase for current session
ulimit -n 65536
# For permanent fix, add to ~/.zshrc or ~/.bash_profile:
echo "ulimit -n 65536" >> ~/.zshrcInstall and use Watchman (recommended):
Metro uses Watchman for file watching on macOS when available — it is more efficient than the native file watcher:
brew install watchman
watchman --version
# Reset Watchman state if it was previously broken
watchman watch-del-allFix 5: Fix Port 8081 Already in Use
Find and kill the process using port 8081:
# Find the process
lsof -i :8081
# Kill it
kill -9 $(lsof -t -i:8081)
# On Windows
netstat -ano | findstr :8081
taskkill /PID <PID> /FOr run Metro on a different port:
npx react-native start --port 8082
# Then in a new terminal, run the app with the custom port:
npx react-native run-ios --port 8082
npx react-native run-android --port 8082
# For Expo:
npx expo start --port 8082Update the app to use the new port (Android):
If you change the Metro port, Android needs to know:
adb reverse tcp:8082 tcp:8082Fix 6: Fix Metro Transform and Babel Errors
Error: SyntaxError or Transform failed:
These usually indicate a Babel configuration issue or a file with syntax Metro cannot parse:
# Check your Babel config
cat babel.config.js// babel.config.js — standard React Native config
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
// Optional: support path aliases (needs babel-plugin-module-resolver)
[
'module-resolver',
{
root: ['./src'],
extensions: ['.ios.js', '.android.js', '.js', '.ts', '.tsx', '.json'],
alias: {
'@components': './src/components',
'@screens': './src/screens',
},
},
],
],
};Fix experimentalDecorators or TypeScript syntax errors:
# Install TypeScript support
npm install --save-dev @babel/plugin-proposal-decorators babel-plugin-parameter-decorator// babel.config.js
module.exports = {
presets: ['module:@react-native/babel-preset'],
plugins: [
['@babel/plugin-proposal-decorators', { legacy: true }],
],
};Clear the Babel cache after changing babel.config.js:
npx react-native start --reset-cacheFix 7: Fix Metro on a Fresh Setup or CI Environment
When setting up a new environment or running in CI:
# Complete setup sequence
git clone https://github.com/your-org/your-app.git
cd your-app
# Install JS dependencies
npm ci
# iOS — install CocoaPods dependencies
cd ios && pod install && cd ..
# Start Metro (in one terminal)
npx react-native start
# Run on device (in another terminal)
npx react-native run-ios
npx react-native run-androidCommon CI issues:
# CI may not have Watchman — disable it in Metro config
// metro.config.js
config.watchman = false; // Fall back to native file watching in CIAndroid — ensure ADB is set up:
# Check connected devices
adb devices
# If no devices found for a running emulator:
adb kill-server && adb start-serveriOS — fix code signing for simulators:
# Simulators do not need code signing — check scheme settings
open ios/YourApp.xcworkspace
# Product → Scheme → Edit Scheme → Run → Build Configuration → DebugStill Not Working?
Check the Metro output for the root error. Metro often shows a long stack trace — scroll to the top to find the original error message, which is more useful than the bottom of the stack.
Verify your Node.js version. React Native has specific Node.js version requirements. Check the project’s .nvmrc or the React Native version’s release notes:
node --version
# Use nvm to switch versions
nvm use 20
nvm install 20Check for symlink issues. If you use npm link or workspaces, Metro may fail to resolve symlinked packages:
// metro.config.js — allow following symlinks
config.resolver.unstable_enableSymlinks = true;Verify Xcode Command Line Tools on macOS:
xcode-select --install
sudo xcode-select --switch /Applications/Xcode.appCheck the device logs for additional error context:
# iOS simulator logs
xcrun simctl spawn booted log stream --level debug | grep -i "react native"
# Android device logs
adb logcat *:E | grep -i "react\|metro\|javascript"For related React and JavaScript bundling issues, see Fix: webpack Module Not Found and Fix: Cannot Use Import Statement Outside a Module.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: Express req.body Is undefined
How to fix req.body being undefined in Express — missing body-parser middleware, wrong Content-Type header, middleware order issues, and multipart form data handling.
Fix: TypeScript Decorators Not Working (experimentalDecorators)
How to fix TypeScript decorators not applying — experimentalDecorators not enabled, emitDecoratorMetadata missing, reflect-metadata not imported, and decorator ordering issues.
Fix: CSS Custom Properties (Variables) Not Working or Not Updating
How to fix CSS custom properties not applying — wrong scope, missing fallback values, JavaScript not setting variables on the right element, and how CSS variables interact with media queries and Shadow DOM.
Fix: Node.js Crashing with UnhandledPromiseRejection (--unhandled-rejections)
How to fix Node.js UnhandledPromiseRejectionWarning and process crashes — why unhandled promise rejections crash Node.js 15+, how to add global handlers, find the source of the rejection, and fix async error handling.