Plane Monorepo Structure Explained: A Deep Dive into the pnpm Workspace Architecture

The Plane monorepo is organized as a pnpm-managed workspace divided into three top-level categories—apps, packages, and configuration files—where independent applications (Next.js web UI, Django API, Node.js live server, and Caddy proxy) consume reusable libraries for UI components, MobX state management, and domain services.

The Plane monorepo structure follows modern open-source architecture patterns by leveraging pnpm workspaces to coordinate multiple applications and shared libraries. As implemented in the makeplane/plane repository, this layout enables teams to develop the web interface, backend API, and real-time collaboration services in isolation while sharing strictly-versioned utilities and TypeScript types across the entire codebase.

Top-Level Architecture

The repository root defines the workspace boundary in pnpm-workspace.yaml, which declares glob patterns for apps/* and packages/* alongside a centralized catalog of pinned external dependencies. This configuration establishes three distinct zones:

  • apps/ – Executable entry points including the Next.js frontend (apps/web), Django REST API (apps/api), real-time Node.js server (apps/live), and Caddy reverse proxy (apps/proxy)
  • packages/ – Reusable libraries published as internal packages, including React UI components, MobX stores, business services, and utility hooks
  • Configuration – Workspace-level tooling including .oxlintrc.json (linting rules), .oxfmtrc.json (formatting rules), and root package.json scripts for dev, build, and test operations

Each package maintains its own tsconfig.json and tsdown.config.ts, allowing independent builds while inheriting shared TypeScript settings from the workspace root.

Apps Directory: Service Entry Points

The apps folder contains four distinct services that constitute the complete Plane deployment stack. Each application owns its deployment lifecycle and runtime environment.

Web Application (Next.js)

The apps/web directory houses the primary user interface built with Next.js and React. This application consumes components from @plane/ui and state from @plane/shared-state to render the project management interface. Key entry points include apps/web/react-router.config.ts for routing configuration and standard Next.js pages for the UI surface.

API Server (Django)

apps/api contains the Django REST API that persists workspace data and handles business logic. The WSGI entry point at apps/api/plane/wsgi.py bootstraps the Python application, exposing endpoints consumed by the web client and external integrations.

Live Collaboration Server (Node.js)

apps/live runs a Node.js server enabling real-time features such as presence indicators and cursor synchronization. Located at apps/live/src/server.ts, this service imports workspace logic from @plane/services to validate permissions during WebSocket connections.

Reverse Proxy (Caddy)

apps/proxy provides a Caddy-based container that routes production traffic to the appropriate backend services, handling TLS termination and load balancing between the web, API, and live servers.

Packages Directory: Shared Libraries

The packages directory contains domain-specific libraries that enforce separation of concerns between presentation, state, and business logic.

UI Components and Design System

packages/ui exports Tailwind-styled React components such as dropdowns, typography scales, and form controls. Components like packages/ui/src/dropdown/single-select.tsx demonstrate the design system implementation, consuming workspace themes and accessibility standards.

State Management with MobX

packages/shared-state centralizes MobX stores that expose domain data to React components. Utilities such as packages/shared-state/src/utils/work-item-filters.helper.ts manage complex filter state, while the main index at packages/shared-state/src/utils/index.ts exports stores for workspace and project data.

Business Logic Services

packages/services encapsulates domain operations including workspace CRUD, notifications, and permissions. The file packages/services/src/workspace/workspace.service.ts defines the WorkspaceService class that both the web app and live server import to maintain consistent business rules.

Utilities and Hooks

packages/utils provides general-purpose TypeScript helpers for file handling and data transformation, while packages/hooks contains React-specific logic such as packages/hooks/src/use-outside-click-detector.tsx for UI interactions. Additional libraries include packages/i18n for internationalization and packages/editor for TipTap-based rich-text integration.

Working with Plane's Code: Practical Examples

The following patterns demonstrate how applications consume packages within the Plane monorepo structure.

Importing UI Components

Import dropdown components from the shared UI library to maintain consistent design patterns:

import { Dropdown } from "@plane/ui";

function ProjectSelector({ projects, selected, onSelect }) {
  return (
    <Dropdown
      value={selected}
      onChange={onSelect}
      options={projects.map(p => ({ value: p.id, label: p.name }))}
      buttonContent="Select project"
      placeholder="Search projects…"
    />
  );
}

Source: packages/ui/src/dropdown/single-select.tsx

Accessing Shared State

Connect React components to MobX stores using the shared-state package:

import { useWorkspaceStore } from "@plane/shared-state";

function WorkspaceHeader() {
  const { workspace } = useWorkspaceStore();
  return <h1>{workspace?.name ?? "Untitled Workspace"}</h1>;
}

Source: packages/shared-state/src/utils/work-item-filters.helper.ts

Calling Domain Services

Execute business logic from the services package across different runtimes:

import { WorkspaceService } from "@plane/services";

async function createWorkspace(name: string) {
  const ws = await WorkspaceService.create({ name });
  console.log("New workspace:", ws.id);
}

Source: packages/services/src/workspace/workspace.service.ts

Using Custom React Hooks

Implement UI behaviors using shared hooks for common interaction patterns:

import { useOutsideClickDetector } from "@plane/hooks";
import { useRef } from "react";

function Modal({ onClose }) {
  const ref = useRef<HTMLDivElement>(null);
  useOutsideClickDetector(ref, onClose, true);
  return <div ref={ref}>Modal content</div>;
}

Source: packages/hooks/src/use-outside-click-detector.tsx

Summary

The Plane monorepo structure demonstrates enterprise-grade organization through strategic separation of concerns:

  • pnpm workspaces coordinate dependencies across apps and packages via pnpm-workspace.yaml and centralized catalog management
  • Four specialized applications handle distinct responsibilities: Next.js for UI, Django for REST API, Node.js for real-time features, and Caddy for traffic routing
  • Seven core packages enforce architectural boundaries between UI components (packages/ui), state containers (packages/shared-state), business services (packages/services), and framework-agnostic utilities (packages/utils)
  • Independent build configurations in each package (tsdown.config.ts, tsconfig.json) enable parallel compilation while maintaining type safety across workspace boundaries

Frequently Asked Questions

What package manager does the Plane monorepo use?

The Plane repository uses pnpm to manage dependencies and workspace linking. The pnpm-workspace.yaml file at the repository root defines the workspace glob patterns (apps/*, packages/*) and specifies a catalog of pinned external dependencies that ensures version consistency across all applications and libraries.

How does the Plane monorepo handle TypeScript compilation?

Each package in the Plane monorepo contains its own tsconfig.json and tsdown.config.ts files, allowing independent compilation while extending shared TypeScript configurations from the workspace root. This setup enables parallel builds during CI/CD pipelines while maintaining strict type checking across package boundaries.

Where is the business logic located in the Plane codebase?

Domain business logic resides in packages/services, specifically in files like packages/services/src/workspace/workspace.service.ts. This separation ensures that both the Next.js web application and the Node.js live server consume identical business rules for workspace operations, notifications, and permissions, preventing logic duplication between frontend and backend contexts.

What is the relationship between apps/web and packages/ui?

The apps/web Next.js application imports React components from packages/ui as a dependency (@plane/ui). This architectural pattern allows the UI library to evolve independently—maintaining its own versioning, testing, and build pipeline—while the web app consumes stable component releases through the pnpm workspace linking mechanism.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →