# How Monorepo Tooling Works in Plane: pnpm Workspaces and TurboRepo Architecture

> Discover how Plane uses pnpm workspaces and TurboRepo for efficient monorepo management, ensuring fast builds and unified dependencies across all projects.

- Repository: [Plane/plane](https://github.com/makeplane/plane)
- Tags: internals
- Published: 2026-06-26

---

**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`](https://github.com/makeplane/plane/blob/main/pnpm-workspace.yaml), which defines the workspace boundaries and dependency resolution rules. This configuration establishes a single [`pnpm-lock.yaml`](https://github.com/makeplane/plane/blob/main/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.

```yaml
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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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.

```json
{
  "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`](https://github.com/makeplane/plane/blob/main/package.json) exposes these through high-level scripts:

```json
{
  "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`](https://github.com/makeplane/plane/blob/main/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:

1. **Install dependencies** – `pnpm install` reads the workspace configuration, resolves the dependency graph, and populates the shared `.pnpm` store.
2. **Start development** – `pnpm dev` launches Turbo’s watch mode across all JavaScript packages simultaneously.
3. **Build for production** – `pnpm build` triggers cached builds that skip unchanged packages.
4. **Verify quality** – `pnpm run check` runs formatting, linting with oxlint, and TypeScript validation.
5. **Fix issues** – `pnpm run fix` automatically resolves formatting and linting violations.

For targeted operations, developers can use the `--filter` flag to run tasks on specific packages:

```bash
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.yaml`](https://github.com/makeplane/plane/blob/main/pnpm-workspace.yaml) manage 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.json`](https://github.com/makeplane/plane/blob/main/turbo.json) define task dependencies with `^build` syntax, enabling parallel execution and intelligent caching of build artifacts.
- **Shared configuration packages** like `typescript-config` and `tailwind-config` distribute 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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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`](https://github.com/makeplane/plane/blob/main/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.