gotchatypescriptreact-nativeModerate
Metro Bundler: Resolving Module Aliases and Monorepo Setup
Viewed 0 times
Metro bundlermodule resolutionpath aliasesmonorepowatchFoldersbabel-plugin-module-resolver
Error Messages
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.