Skip to main content

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

1

Initialize the monorepo

2

Configure workspaces

package.json
3

Create the Expo app

Update apps/mobile/package.json:
4

Create shared packages

packages/ui/package.json
5

Link packages

In apps/mobile/package.json:
Then run:

Setup with pnpm

1

Initialize with pnpm

2

Create pnpm-workspace.yaml

pnpm-workspace.yaml
3

Configure .npmrc

.npmrc
React Native and Expo require hoisting due to their native module resolution.
4

Install dependencies

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

EAS Build Configuration

apps/mobile/eas.json

.easignore

Prevent uploading unnecessary files:
apps/mobile/.easignore

Troubleshooting

Ensure your metro.config.js is configured correctly:
Clear Metro cache:
Native modules must be installed in the app’s node_modules:
Or hoist with pnpm:
.npmrc
Check your tsconfig.json paths:
Restart TypeScript server in your editor.
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
Run with: