Skip to main content
Metro is the JavaScript bundler for React Native. It takes all your JavaScript code and dependencies and bundles them into a single file that can be loaded by your application.

Overview

Metro is configured through metro.config.js in your project root. React Native provides sensible defaults through the @react-native/metro-config package.

Basic Configuration

Create or modify metro.config.js in your project root:
const {getDefaultConfig, mergeConfig} = require('@react-native/metro-config');

const config = {};

module.exports = mergeConfig(getDefaultConfig(__dirname), config);

Default Configuration

The @react-native/metro-config package provides these defaults:

Resolver Configuration

resolver: {
  resolverMainFields: ['react-native', 'browser', 'main'],
  platforms: ['android', 'ios'],
  unstable_conditionNames: ['react-native'],
}

Server Configuration

server: {
  port: Number(process.env.RCT_METRO_PORT) || 8081,
}

Transformer Configuration

transformer: {
  allowOptionalDependencies: true,
  assetRegistryPath: 'react-native/Libraries/Image/AssetRegistry',
  babelTransformerPath: '@react-native/metro-babel-transformer',
  getTransformOptions: async () => ({
    transform: {
      experimentalImportSupport: false,
      inlineRequires: true,
    },
  }),
}

Common Configurations

Adding Custom File Extensions

const config = {
  resolver: {
    sourceExts: ['jsx', 'js', 'ts', 'tsx', 'json'],
  },
};

Configuring Asset Extensions

const config = {
  resolver: {
    assetExts: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'],
  },
};

Adding Watch Folders (Monorepos)

const path = require('path');

const config = {
  watchFolders: [
    path.resolve(__dirname, '../shared-package'),
  ],
};

Custom Transformer

const config = {
  transformer: {
    babelTransformerPath: require.resolve('./customTransformer.js'),
  },
};

Advanced Features

Inline Requires

Inline requires improve startup performance by lazily loading modules:
transformer: {
  getTransformOptions: async () => ({
    transform: {
      inlineRequires: true,
    },
  }),
}
Before (without inline requires):
const MyComponent = require('./MyComponent');

function App() {
  return <MyComponent />;
}
After (with inline requires):
function App() {
  const MyComponent = require('./MyComponent');
  return <MyComponent />;
}

Custom Resolver

const config = {
  resolver: {
    resolveRequest: (context, moduleName, platform) => {
      // Custom resolution logic
      if (moduleName === 'my-custom-module') {
        return {
          filePath: path.resolve(__dirname, 'custom-path.js'),
          type: 'sourceFile',
        };
      }
      return context.resolveRequest(context, moduleName, platform);
    },
  },
};

Source Map Configuration

const config = {
  serializer: {
    createModuleIdFactory: () => {
      return (path) => {
        // Generate stable module IDs
        return path;
      };
    },
  },
};

Symbolicator Configuration

Metro includes a symbolicator for stack trace processing:
const config = {
  symbolicator: {
    customizeFrame: (frame) => {
      const collapse = Boolean(
        frame.file != null && /node_modules/.test(frame.file)
      );
      return {collapse};
    },
  },
};
This collapses node_modules frames in LogBox for cleaner error displays.

Performance Optimization

Caching

Metro caches transformed files for faster subsequent builds:
const config = {
  cacheStores: [
    new FileStore({
      root: path.join(__dirname, '.metro-cache'),
    }),
  ],
};

Parallel Processing

const config = {
  maxWorkers: 4, // Number of worker threads
};

Tree Shaking

Tree shaking is experimental in React Native. Test thoroughly when enabling.
transformer: {
  getTransformOptions: async () => ({
    transform: {
      experimentalImportSupport: true,
    },
  }),
}

Platform-Specific Code

Metro automatically resolves platform-specific files:
MyComponent.js         // Fallback
MyComponent.ios.js     // iOS-specific
MyComponent.android.js // Android-specific
Configuration:
resolver: {
  platforms: ['ios', 'android', 'web'],
}

Asset Handling

Image Resolution

Metro handles image resolution automatically:
resolver: {
  assetExts: ['png', 'jpg', 'jpeg', 'gif', 'webp'],
  // Metro will find:
  // icon.png
  // [email protected]
  // [email protected]
}

Custom Asset Plugins

const config = {
  transformer: {
    assetPlugins: ['my-custom-asset-plugin'],
  },
};

Monorepo Support

Yarn Workspaces

const path = require('path');
const fs = require('fs');

// Get workspace packages
const workspaces = require('./package.json').workspaces.packages;

const config = {
  watchFolders: workspaces.map(workspace => 
    path.resolve(__dirname, '../', workspace)
  ),
  resolver: {
    nodeModulesPaths: [
      path.resolve(__dirname, 'node_modules'),
      path.resolve(__dirname, '../node_modules'),
    ],
  },
};

Environment Variables

Metro Port

# Change Metro port
RCT_METRO_PORT=8088 npx react-native start

Reset Cache

npx react-native start --reset-cache

Troubleshooting

Clear Metro Cache

rm -rf $TMPDIR/metro-* && rm -rf $TMPDIR/haste-*

Common Issues

This usually means Metro can’t find the file:
  1. Check the import path is correct
  2. Verify the file exists
  3. Add the extension to resolver.sourceExts
  4. Check watchFolders for monorepos
  5. Clear Metro cache
Try these solutions:
  1. Clear Metro cache: npx react-native start --reset-cache
  2. Reduce maxWorkers in config
  3. Check for circular dependencies
  4. Update Node.js to latest LTS version
  5. Increase Node memory: NODE_OPTIONS=--max_old_space_size=4096
Optimize Metro performance:
  1. Enable inlineRequires transformer option
  2. Use watchFolders only when necessary
  3. Exclude unnecessary folders from watching
  4. Increase maxWorkers for parallel processing
  5. Use SSD for faster file system access

Metro CLI Commands

# Start Metro bundler
npx react-native start

# Reset cache
npx react-native start --reset-cache

# Custom port
npx react-native start --port 8088

# Verbose output
npx react-native start --verbose

Next Steps

Fast Refresh

Learn about Fast Refresh feature

Debugging

Debug your React Native apps

Build docs developers (and LLMs) love