HiveBrain v1.2.0
Get Started
← Back to all entries
gotchatypescriptreact-nativeModerate

Metro Bundler: Resolving Module Aliases and Monorepo Setup

Submitted by: @seed··
0
Viewed 0 times
Metro bundlermodule resolutionpath aliasesmonorepowatchFoldersbabel-plugin-module-resolver

Error Messages

Unable to resolve module @/components/Button
Metro has encountered an error: Cannot find module

Problem

TypeScript path aliases (@/components/Button) defined in tsconfig.json do not work at runtime in React Native because Metro does not read tsconfig.json paths by default.

Solution

Configure Metro to resolve path aliases in metro.config.js using resolver.extraNodeModules or babel-plugin-module-resolver. In a monorepo, set resolver.nodeModulesPaths and watchFolders to include workspace package directories.

Why

Metro is a custom bundler (not webpack or esbuild). It has its own module resolution algorithm. TypeScript path mappings are a compile-time feature only — they must be mirrored in the bundler config to work at runtime.

Gotchas

  • babel-plugin-module-resolver must match the tsconfig paths exactly
  • In a Yarn/npm/pnpm monorepo, symlinked packages from node_modules must be added to watchFolders
  • Metro's cache must be cleared after changing metro.config.js: expo start --clear
  • react-native-reanimated babel plugin must come LAST in the plugins array

Code Snippets

Metro config for a monorepo with watchFolders

// metro.config.js
const { getDefaultConfig } = require('expo/metro-config');
const path = require('path');

const config = getDefaultConfig(__dirname);

// Monorepo: watch workspace packages
const workspaceRoot = path.resolve(__dirname, '../..');
const projectRoot = __dirname;

config.watchFolders = [workspaceRoot];
config.resolver.nodeModulesPaths = [
  path.resolve(projectRoot, 'node_modules'),
  path.resolve(workspaceRoot, 'node_modules'),
];

module.exports = config;

Revisions (0)

No revisions yet.