Plane Project Monorepo Structure: A Deep Dive into the pnpm and Turbo Architecture
Plane uses a pnpm-managed monorepo that consolidates frontend applications, backend services, and shared TypeScript libraries under a single repository coordinated by TurboRepo.
The makeplane/plane repository organizes a complex product ecosystem—including the main web UI, admin panels, real-time collaboration servers, and reusable utility libraries—into a unified workspace. Understanding this Plane project monorepo structure helps developers navigate the codebase, run cross-application builds, and contribute new features efficiently.
Workspace Configuration and Root Setup
The monorepo's foundation is defined in pnpm-workspace.yaml at the repository root. This file instructs pnpm which directories to include in the workspace while explicitly excluding certain backend services that ship as Docker containers.
# https://github.com/makeplane/plane/blob/preview/pnpm-workspace.yaml
packages:
- apps/* # All UI apps (web, admin, space, live, etc.)
- packages/* # Shared TypeScript libraries (utils, logger, i18n, etc.)
- "!apps/api" # API server is built separately (Docker image)
- "!apps/proxy" # Proxy service is also excluded
The root directory also houses global configuration files including package.json with workspace-wide scripts, turbo.json for task orchestration, and shared linting configurations. These files ensure consistent tooling standards across all workspace members while allowing individual apps to customize their specific build pipelines.
Apps Directory: The Application Layer
The apps/ folder contains standalone, runnable applications that represent the various user-facing and service components of Plane. Each application maintains its own build configuration, dependencies, and deployment strategy.
Web Application
The primary user interface lives in apps/web/ and is built with Vite. It uses @react-router/dev/vite for the development server and vite-tsconfig-paths to resolve TypeScript path aliases relative to its local tsconfig.json.
// https://github.com/makeplane/plane/blob/preview/apps/web/vite.config.ts
import { defineConfig } from "vite";
import { reactRouter } from "@react-router/dev/vite";
import tsconfigPaths from "vite-tsconfig-paths";
import path from "path";
export default defineConfig(() => ({
plugins: [
reactRouter(),
tsconfigPaths({ projects: [path.resolve(__dirname, "tsconfig.json")] })
],
// …
}));
Admin and Space Interfaces
- Admin UI (
apps/admin/): Provides administrative controls with its own Vite configuration and MobX state management stores located inapps/admin/store/ - Space UI (
apps/space/): Handles workspace-specific functionality as a separate deployable unit
Live Collaboration Service
The apps/live/ directory contains a Node.js-based real-time server that handles WebSocket connections for collaborative features. Unlike the frontend apps, this service runs its own TypeScript build process and test suite independently.
Excluded Services
Both apps/api and apps/proxy are excluded from the JavaScript workspace because they are designed to run as containerized services with their own dependency management and build lifecycles.
Packages Directory: Shared Libraries
The packages/ directory houses reusable TypeScript libraries consumed by multiple applications. These modules enforce the Don't Repeat Yourself (DRY) principle across the Plane project monorepo structure.
Core Shared Modules
packages/utils/: Generic helpers for workspace handling, date manipulation, and data transformationpackages/logger/: Express middleware used by both frontend and backend services, exported frompackages/logger/src/middleware.tspackages/i18n/: Centralized internationalization containing locale JSON files (such aspackages/i18n/src/locales/zh-CN/workspace.json) and translation utilitiespackages/hooks/: Shared React hooks for data fetching and state synchronizationpackages/editor/: Rich text editing components and utilitiespackages/decorators/: TypeScript decorators for cross-cutting concerns
Cross-Cutting Logger Example
The logger package demonstrates how shared infrastructure code bridges frontend and backend concerns:
// https://github.com/makeplane/plane/blob/preview/packages/logger/src/middleware.ts
import { Request, Response, NextFunction } from "express";
export function requestLogger(req: Request, res: Response, next: NextFunction) {
console.log(`${req.method} ${req.path}`);
next();
}
Build Orchestration with TurboRepo
Plane leverages TurboRepo to execute tasks across the workspace in parallel while respecting dependency graphs. The root package.json defines high-level orchestration scripts that delegate to individual package scripts.
// https://github.com/makeplane/plane/blob/preview/package.json
{
"scripts": {
"dev": "turbo run dev --concurrency=18",
"build": "turbo run build",
"check": "turbo run check",
"fix": "turbo run fix"
}
}
Running pnpm dev initiates development servers for all workspace applications simultaneously—typically binding web to port 3000, admin to port 3001, and others—while watching for changes in shared packages/* dependencies. The --concurrency=18 flag ensures adequate parallel process allocation for the workspace size.
Linting, type-checking, and code formatting are similarly coordinated through Turbo. The pnpm check command runs validation across every package, while pnpm fix applies automated corrections using tools like oxlint throughout the repository.
Working with the Monorepo
Adding New Workspace Members
To extend the Plane project monorepo structure with new functionality:
- Create a directory under
apps/(for applications) orpackages/(for libraries) - Initialize a
package.jsonwith a unique scoped name (e.g.,"@plane/new-lib") - Reference workspace dependencies using the
workspace:*protocol - Execute
pnpm installto generate symlinks automatically
Importing Workspace Dependencies
Applications consume shared libraries via the workspace protocol, ensuring they always receive the local version during development:
// apps/web/src/components/example.tsx
import { formatDate } from "@plane/utils";
export const Example = () => <div>{formatDate(new Date())}</div>;
Targeted Script Execution
Developers can run commands for specific packages without navigating to their directories:
# Build only the admin UI
pnpm --filter @plane/admin run build
# Run type checking on the logger package only
pnpm --filter @plane/logger run check
Summary
- pnpm workspaces define the monorepo boundaries in
pnpm-workspace.yaml, including theapps/*andpackages/*glob patterns while excluding containerized services likeapps/api - Application isolation allows
web,admin,space, andliveto maintain independent Vite or Node.js build configurations while sharing code - Library reusability is enforced through
packages/*modules includingutils,logger,i18n, andhooksthat export TypeScript code consumed via theworkspace:*protocol - TurboRepo orchestration provides parallel execution of
dev,build,check, andfixcommands across the entire graph with intelligent caching - Developer ergonomics support filtering commands to specific packages and automatic symlink management when adding new workspace members
Frequently Asked Questions
How does Plane handle dependency management between apps and packages?
Plane uses pnpm's workspace protocol to link packages internally. When an app like web depends on @plane/utils, it specifies "@plane/utils": "workspace:*" in its package.json. During pnpm install, pnpm creates symlinks pointing to the local packages/utils directory, ensuring changes to shared code immediately reflect across consuming applications without publishing to npm.
Why are the API and Proxy services excluded from the pnpm workspace?
The apps/api and apps/proxy directories are excluded via the !apps/api and !apps/proxy patterns in pnpm-workspace.yaml because they are designed to run as containerized services with distinct runtime environments. These services manage their own dependencies and build processes within Docker images, separate from the JavaScript/TypeScript toolchain that powers the frontend applications and shared libraries.
What is the purpose of the live application in the monorepo?
The apps/live/ directory contains a Node.js real-time collaboration server that handles WebSocket connections for live editing and synchronization features. Unlike the static frontend applications built with Vite, this service requires a persistent Node process and is developed as a first-class workspace member, allowing it to import shared utilities like @plane/logger while maintaining its own TypeScript compilation and testing pipeline.
How can I run development servers for specific applications only?
Use pnpm's filter flag combined with Turbo to target specific workspace members. For example, pnpm --filter @plane/web run dev starts only the web application, while pnpm --filter @plane/web --filter @plane/admin run dev starts both the web and admin interfaces simultaneously. This approach conserves system resources when you only need to work on a subset of the Plane project monorepo structure.
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 →