PNPM
This document provides a complete guide for using PNPM in a monorepo setup with Expo React Native and TypeScript.
What is PNPM?
PNPM is a fast, disk-efficient package manager for Node.js projects. It is designed to handle monorepos efficiently by using a content-addressable storage system, avoiding duplicated node_modules, and supporting workspaces natively.
Benefits
- Monorepo-friendly: Manages multiple packages in one repository efficiently.
- Disk-space efficient: Stores each package only once on your disk.
- Fast installation: Uses caching and symlinks to speed up dependency installs.
- Strict dependency resolution: Ensures consistent dependency trees across workspaces.
- Workspace support: Enables running scripts and commands across packages easily.
Installing PNPM
Global Installation
npm install -g pnpm
Check the version:
pnpm -v
Project Setup
Initialize a new monorepo:
mkdir my-monorepo
cd my-monorepo
pnpm init
Monorepo Structure
A typical monorepo structure with PNPM looks like this:
my-monorepo/
apps/
mobile/ # Expo React Native app
backend/ # Optional backend/API
packages/
ui/ # Shared UI components
utils/ # Shared TypeScript utilities
config/ # Shared ESLint/TS/Prettier configs
pnpm-workspace.yaml
package.json
pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
This file tells PNPM which directories are workspaces. Each workspace can depend on others, and PNPM will link them automatically.
Root package.json
{
"name": "my-monorepo",
"private": true,
"devDependencies": {
"typescript": "^5.3.0",
"eslint": "^8.50.0"
},
"scripts": {
"dev": "pnpm -r run dev",
"build": "pnpm -r run build",
"lint": "pnpm -r run lint",
"typecheck": "pnpm -r run typecheck",
"clean": "pnpm -r run clean"
}
}
Notes:
-r(or--recursive) tells PNPM to run scripts in all workspaces.private: trueensures this repository is not accidentally published.
Example Workspace: Mobile App (apps/mobile/package.json)
{
"name": "mobile",
"private": true,
"scripts": {
"dev": "expo start",
"build": "expo export",
"lint": "eslint . --ext .ts,.tsx",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"expo": "^49.0.0",
"react-native": "0.72.0"
}
}
devstarts the Expo development server.buildexports the app for production.lintandtypecheckenforce code quality.
Example Workspace: Shared UI Package (packages/ui/package.json)
{
"name": "ui",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc --build",
"lint": "eslint src/",
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"react": "^18.2.0",
"react-native": "*"
}
}
- PNPM will link this package to dependent workspaces automatically.
- Use
pnpm installafter changing dependencies to ensure links are updated.
Running Scripts Across Workspaces
Start dev servers for all apps
pnpm -r run dev
Build all packages and apps
pnpm -r run build
Lint all workspaces
pnpm -r run lint
Typecheck everything
pnpm -r run typecheck
Targeting a Specific Workspace
Run dev only for mobile
pnpm --filter mobile run dev
Run lint only for ui package
pnpm --filter ui run lint
PNPM supports workspace filtering, allowing you to focus on a specific app or package.
Managing Dependencies
- Install dependency for a specific workspace:
pnpm add react-native --workspace mobile
- Install dev dependency for all workspaces:
pnpm add -D typescript -r
- Remove a dependency:
pnpm remove <package> --workspace <workspace-name>
Best Practices
- Keep apps/ minimal; push reusable code into packages/.
- Use workspace linking instead of relative paths for shared packages.
- Centralize configs (
eslint,tsconfig,prettier) in packages/config/. - Use
peerDependenciesfor shared React/React Native versions. - Use
pnpm filterfor targeted builds and faster iteration.
Troubleshooting & Tips
- Node_modules duplication: PNPM avoids duplication automatically; check
pnpm-lock.yamlif conflicts arise. - Symlink issues: Ensure your IDE supports PNPM symlinks for TypeScript resolution.
- Expo Metro issues: Use
expo start -cto clear the cache. - Dependency mismatch: Always use
pnpm -r installafter updating workspace dependencies.
Summary
PNPM enables fast, consistent monorepo management for Expo React Native and TypeScript:
- Efficient workspace linking and dependency resolution.
- Recursive scripts across apps and packages.
- Supports filtering and targeted workspace commands.
- Saves disk space while ensuring strict dependency consistency.