Monorepo Foundations
Monorepo Foundations
Our project utilizes a monorepo architecture managed by pnpm and Turborepo to streamline development, ensure consistency, and optimize build processes across multiple applications and shared packages.
Core Concepts
- pnpm Workspaces: Manages dependencies across the entire project, allowing shared libraries and efficient installation.
- Turborepo: Provides intelligent build caching and task orchestration, significantly speeding up builds and tests.
Package Management
- pnpm is the designated package manager (v10.6.5 or higher).
- Use
workspace:*syntax inpackage.jsonfiles to link internal packages. - Install all dependencies from the root directory:
pnpm install
Workspace Structure
The monorepo is organized into two primary directories at the root:
apps/: Contains deployable applications.web/: The main web application (Vite + React Router).native/: The React Native mobile application (Expo).
packages/: Contains shared libraries, utilities, and configurations used across applications.api/: Backend API server (Hono) and client types.api-hooks/: TanStack Query hooks generated from the API spec.auth/: Authentication logic and utilities.config/: Shared configurations (ESLint, TypeScript, etc.).database/: Drizzle ORM schema, client, and migration utilities.email/: Email templates and sending logic.i18n/: Internationalization setup.payments/: Payment provider integrations (e.g., Stripe).push-notifications/: Push notification setup.storage/: Cloud storage utilities.typescript-config/: Base TypeScript configurations.
Common Commands
Execute these commands from the root of the monorepo:
# Install all dependencies
pnpm install
# Start all applications in development mode
pnpm dev
# Build all applications and packages
pnpm build
# Run linters across the codebase
pnpm lint
# Run tests for all packages
pnpm test
# Clean all build artifacts and node_modules
pnpm clean
# Start a specific application (e.g., web)
pnpm --filter web dev
# Run a command within a specific package (e.g., generate DB migrations)
pnpm --filter @repo/database db:generateAdding Dependencies
Always use pnpm with the --filter flag to add dependencies to specific packages:
# Add a production dependency to 'web' app
pnpm --filter web add react-map-gl
# Add a development dependency to 'api' package
pnpm --filter @repo/api add -D @types/nodeAdd shared development tools (like linters, test runners) to the root package.json:
# Add husky as a root development dependency
pnpm add -Dw huskyCreating New Packages
- Create the new directory under
packages/(e.g.,packages/new-utility). - Initialize a
package.json(e.g.,pnpm init). Ensure the package name is scoped (e.g.,@repo/new-utility). - Set up
tsconfig.json, extending from@repo/typescript-config/base.json. - Add necessary build/dev scripts to its
package.json. - Update
pnpm-workspace.yamlif necessary (usually automatic forpackages/*). - Configure its pipeline tasks in the root
turbo.json.
Turborepo (turbo.json)
Turborepo orchestrates tasks defined in the pipeline section of turbo.json. Key aspects include:
- Task Dependencies (
dependsOn): Defines the execution order (e.g.,builddepends on^build, meaning build dependencies first). - Caching (
cache,outputs): Specifies which files/outputs to cache, speeding up subsequent runs. - Inputs: Defines files/env variables that influence a task's output. Changes to inputs invalidate the cache.
Refer to the root turbo.json for the specific pipeline configuration.