Overview
Monorepos allow you to manage multiple packages in a single repository. This is useful for sharing code between your Expo app, web app, and shared packages.Common Monorepo Structure
Setup with Yarn Workspaces
Setup with pnpm
Configure .npmrc
.npmrc
React Native and Expo require hoisting due to their native module resolution.
Setup with npm Workspaces
package.json
Metro Configuration
Configure Metro for monorepos
apps/mobile/metro.config.js
For Yarn 2+ (Berry)
apps/mobile/metro.config.js
TypeScript Configuration
Root tsconfig.json
tsconfig.json
App-specific tsconfig
apps/mobile/tsconfig.json
Package tsconfig
packages/ui/tsconfig.json
Shared Package Examples
UI Component Package
packages/ui/src/Button.tsx
packages/ui/src/index.ts
API Client Package
packages/api/src/client.ts
Shared Config Package
packages/config/src/theme.ts
Using Shared Packages
apps/mobile/app/index.tsx
Running Commands
- Yarn
- pnpm
- npm
EAS Build Configuration
apps/mobile/eas.json
.easignore
Prevent uploading unnecessary files:apps/mobile/.easignore
Troubleshooting
Metro can't find modules from workspace packages
Metro can't find modules from workspace packages
Ensure your Clear Metro cache:
metro.config.js is configured correctly:Native modules not working
Native modules not working
Native modules must be installed in the app’s node_modules:Or hoist with pnpm:
.npmrc
TypeScript can't find shared packages
TypeScript can't find shared packages
EAS Build fails with workspace packages
EAS Build fails with workspace packages
Ensure
.easignore doesn’t exclude workspace packages:Best Practices
- Hoist React Native dependencies: Use hoisting patterns to avoid duplicate native modules
- Use workspace protocol: Reference local packages with
"@my-app/ui": "*"or"workspace:*" - Share configs: Keep ESLint, Prettier, and TypeScript configs in shared packages
- Version together: Use tools like Changesets for coordinated versioning
- Clear caches frequently: Metro, TypeScript, and bundler caches can cause issues
- Test in isolation: Ensure packages work independently
- Document dependencies: Make it clear which packages depend on React Native
- Use path aliases: Configure TypeScript paths for cleaner imports
Advanced: Turborepo Integration
turbo.json