How Monorepo Tooling Works in Plane: pnpm Workspaces and TurboRepo Architecture
Plane orchestrates its JavaScript packages using a pnpm workspace for unified dependency management and TurboRepo for cached, parallel task execution across apps and shared libraries.
The Plane repository employs a sophisticated monorepo tooling setup to streamline development across its React applications and shared utility packages. By combining pnpm workspaces with TurboRepo pipelines, the project achieves deterministic dependency resolution and incremental builds that only reprocess changed code. This architecture supports the main web app, admin interfaces, and component libraries while excluding the Python-based API services.
Workspace Configuration in pnpm-workspace.yaml
The foundation of Plane’s monorepo tooling resides in pnpm-workspace.yaml, which defines the workspace boundaries and dependency resolution rules. This configuration establishes a single pnpm-lock.yaml at the root while creating symlinked node_modules for each package.
Package Layout and Exclusions
The workspace maps two primary directories: apps/* for applications and packages/* for shared libraries. However, the configuration explicitly excludes Python services from the JavaScript dependency graph.
packages:
- apps/*
- packages/*
- "!apps/api"
- "!apps/proxy"
The ! prefix keeps apps/api and apps/proxy out of pnpm’s scope, allowing the package manager to focus exclusively on Node-based code while the Python backend operates independently.
Dependency Catalogs and Overrides
Plane uses catalog entries to centralize version management. The catalog: prefix in pnpm-workspace.yaml ensures consistent dependency versions across all packages. For example, when @storybook/react is defined as "catalog:" in a package’s package.json, pnpm resolves it to the centralized version defined in the workspace file.
The configuration also includes an overrides block that forces specific versions or pins transitive dependencies to prevent version drift, ensuring reproducible builds across developer environments.
Task Orchestration with TurboRepo
TurboRepo serves as the task runner that coordinates builds, tests, and checks across the monorepo. Defined in turbo.json, the pipeline creates a dependency graph where tasks can declare prerequisites and output caching rules.
Build Pipeline Configuration
The build task forms the core of the deployment pipeline. Each package runs its local build script—typically vite build for applications or tsc for libraries—while respecting topological order.
{
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
}
}
The ^build dependency ensures Turbo builds parent packages before their dependents, while the dist/** output pattern enables caching of build artifacts.
Development and Quality Check Tasks
Turbo distinguishes between production builds and development workflows. The dev task starts watch mode for all packages concurrently with caching disabled for rapid feedback.
| Task | Purpose | Caching | Dependencies |
|---|---|---|---|
dev |
Watch mode development | No | ^build |
check:lint |
oxlint execution | No | — |
check:types |
TypeScript checking | No | ^build |
fix:* |
Auto-formatting and fixes | No | — |
The root package.json exposes these through high-level scripts:
{
"scripts": {
"dev": "turbo run dev --concurrency=18",
"build": "turbo run build",
"check": "turbo run check",
"fix": "turbo run fix"
}
}
Running pnpm dev invokes the development pipeline with 18 concurrent processes, while pnpm run check executes linting, formatting verification, and type-checking across the entire repository.
Shared Configuration Packages
Plane centralizes build tooling through dedicated packages that eliminate configuration duplication. The packages/typescript-config/base.json provides the base TypeScript compiler options that individual packages extend via "extends": "../../packages/typescript-config/base.json".
Similarly, packages/tailwind-config and packages/postcss distribute styling configurations, ensuring consistent CSS processing across the web app, admin panel, and UI component library. This pattern allows changes to shared tooling to propagate instantly to all dependent packages.
Daily Development Workflow
The monorepo tooling enables a single-command developer experience. After cloning the repository, the workflow follows these distinct phases:
- Install dependencies –
pnpm installreads the workspace configuration, resolves the dependency graph, and populates the shared.pnpmstore. - Start development –
pnpm devlaunches Turbo’s watch mode across all JavaScript packages simultaneously. - Build for production –
pnpm buildtriggers cached builds that skip unchanged packages. - Verify quality –
pnpm run checkruns formatting, linting with oxlint, and TypeScript validation. - Fix issues –
pnpm run fixautomatically resolves formatting and linting violations.
For targeted operations, developers can use the --filter flag to run tasks on specific packages:
pnpm turbo run build --filter=@plane/ui
This command builds only the UI library and its dependencies, reducing CI time and local debugging cycles.
Summary
- pnpm workspaces in
pnpm-workspace.yamlmanage the JavaScript dependency graph while excluding Python services (apps/api,apps/proxy) from Node module resolution. - Catalog entries centralize version control across packages, preventing dependency drift through the
catalog:prefix and override blocks. - TurboRepo pipelines in
turbo.jsondefine task dependencies with^buildsyntax, enabling parallel execution and intelligent caching of build artifacts. - Shared configuration packages like
typescript-configandtailwind-configdistribute tooling standards across all apps and libraries. - Root npm scripts provide unified commands (
pnpm dev,pnpm build,pnpm run check) that orchestrate the entire repository with a single command.
Frequently Asked Questions
Why does Plane exclude apps/api from the pnpm workspace?
The apps/api directory contains Python-based backend services that do not use Node.js dependencies. By excluding apps/api and apps/proxy in pnpm-workspace.yaml, pnpm avoids attempting to install JavaScript packages in these directories, keeping the dependency graph focused on the TypeScript and React applications while allowing the Python services to manage their own requirements independently.
How does TurboRepo caching improve build times in Plane?
TurboRepo caches task outputs based on the outputs and inputs declarations in turbo.json. When a package’s source files haven’t changed since the last build, Turbo retrieves the cached dist/** artifacts instead of re-executing the build script. This incremental approach means that in a repository with dozens of packages, developers only wait for builds of code that actually changed, reducing CI times and local development latency.
What is the difference between pnpm dev and pnpm build in Plane?
pnpm dev invokes turbo run dev --concurrency=18, which starts development servers in watch mode across all packages with caching disabled for immediate feedback during coding. pnpm build runs turbo run build, which produces optimized production bundles with caching enabled. The development command prioritizes speed and hot-reloading through Vite, while the build command focuses on creating deployable artifacts with full dependency resolution.
How do shared TypeScript configurations propagate to individual packages?
The packages/typescript-config/base.json file contains the canonical compiler options for the repository. Individual packages reference this configuration through relative paths in their local tsconfig.json files using "extends": "../../packages/typescript-config/base.json". When the base configuration changes, all extending packages automatically adopt the new settings on their next type-check, ensuring consistent strictness rules and compiler options across the entire monorepo without manual updates to each package.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →