makeplane/plane Project Structure: A Complete Guide to the Monorepo Architecture

The makeplane/plane repository is a pnpm-based monorepo that organizes runnable services under apps/ and shared libraries under packages/, bound together by a workspace definition in pnpm-workspace.yaml.

This open-source project management platform separates deployment targets from reusable code through a clean dual-directory layout. Understanding this structure is essential for contributing to Plane or deploying custom instances, as it dictates how dependencies resolve, builds execute, and services communicate.

Workspace Configuration and Root Layout

At the repository root, pnpm-workspace.yaml defines the monorepo boundaries and dependency catalog. This file instructs pnpm to treat specific directories as workspace members while excluding legacy services from the Node.js toolchain.


# pnpm-workspace.yaml

packages:
  - apps/*
  - packages/*
  - "!apps/api"
  - "!apps/proxy"

The apps/* pattern includes every deployable service, while packages/* captures shared TypeScript libraries. The exclusion entries (!apps/api and !apps/proxy) are critical architectural decisions: these services are pure Python/Django projects that operate outside the Node.js dependency graph, preventing tooling conflicts while keeping code colocated.

Top-Level Directory Organization

The repository root contains four primary organizational zones that separate runtime concerns from development infrastructure.

  • apps/ – Contains all deployable services, including the React front-end (web/), admin console (admin/), document export engine (live/), and Python REST API (api/).
  • packages/ – Houses reusable TypeScript modules consumed via workspace:* specifiers, including UI components (ui/), utilities (utils/), and type definitions (types/).
  • docs/ – Hosts documentation assets such as linting guides and architectural decision records.
  • Docker Compose Files – docker-compose.yml and docker-compose-test.yml orchestrate the Postgres database, Redis cache, Python API, and Node.js apps for local development.

Applications in the apps/ Directory

Each entry in apps/ represents an independently deployable service with its own package.json, build pipeline, and runtime requirements.

web – Primary User Interface

Located at apps/web/, this React application serves as the main project management interface. Its package.json defines standard scripts: dev for Vite-powered hot reloading, build for production bundling, and check:lint/check:types for quality gates. The app consumes shared workspace packages using imports such as import { Button } from '@plane/ui'.

admin – Administrative Console

The apps/admin/ directory contains the instance administration UI, sharing identical tooling and scripts with the web app. It leverages @plane/hooks for authentication logic and @plane/services for API communication.

live – Document Export Service

Housed in apps/live/, this Node.js service handles server-side PDF and RTF generation. Unlike the browser-targeted apps, this service runs as a backend process but still participates in the workspace dependency graph, importing shared utilities from @plane/utils.

api – Python Django Backend

The apps/api/ directory breaks from the Node.js pattern, containing a Django REST framework application. Because Python dependencies are managed separately, this folder is excluded from the pnpm workspace. The API exposes endpoints defined in files such as apps/api/plane/web/views.py, which the React front-ends access over HTTP.

Shared Libraries in the packages/ Directory

The packages/ directory implements the "build once, use everywhere" philosophy through granular, single-responsibility modules. Each package is a standard npm module that resolves locally via the workspace:* specifier.

@plane/ui – The component library located at packages/ui/ provides Tailwind-styled React components and Storybook documentation. Source files live in packages/ui/src/ and export design-system primitives like buttons, avatars, and form inputs.

@plane/types – Centralized TypeScript definitions stored in packages/types/ ensure API contract consistency. Front-end apps and utility functions import interfaces such as Issue or IWorkspace here, creating type safety across the JavaScript/Python boundary.

@plane/utils – Generic helper functions for URL manipulation, string validation, and data transformation reside in packages/utils/. For example, packages/utils/src/workspace.ts exports orderWorkspacesList, a utility used by both web and admin apps.

@plane/shared-state – MobX stores for global state management live here, synchronizing complex UI state (current workspace, selected views) across the web and admin applications without prop drilling.

@plane/i18n – Internationalization utilities built on i18next provide translation infrastructure that both front-end apps consume through react-i18next.

Build Orchestration and Development Tooling

The monorepo employs a unified toolchain orchestrated by Turbo and pnpm catalogs to ensure consistent builds across disparate services.

Vite drives all front-end builds via vite.config.ts files in each JavaScript app, offering fast HMR and optimized production bundles.

OxLint and OxFmt enforce code quality project-wide through scripts defined in each package.json: check:lint validates code, while fix:lint applies automatic corrections.

Turbo coordinates the build graph via turbo.json, enabling parallel execution and aggressive caching of packages/ builds when their source hasn't changed.

Docker provides the integration layer for polyglot services. The root docker-compose.yml spins up the Python API, Postgres, Redis, and the Node.js apps simultaneously, ensuring the web app can communicate with apps/api during local development.

Cross-Cutting Integration Patterns

Understanding how these structural elements interact reveals the architectural integrity of the system.

Workspace Resolution – When apps/web/src/components/IssueCard.tsx imports import { Avatar } from '@plane/ui', pnpm resolves this to the local file system at packages/ui/src/, enabling zero-config cross-package development.

Type Consistency – All TypeScript apps import domain models from @plane/types, guaranteeing that the shape of a "Workspace" or "Issue" in the React code matches the Django serializer definitions in apps/api/plane/web/views.py.

State Synchronization – The @plane/shared-state MobX stores persist user session data and UI preferences in memory, allowing seamless state sharing between the main app and admin console without complex message passing.

Summary

  • The makeplane/plane repository uses a pnpm workspace defined in pnpm-workspace.yaml to link apps/* and packages/* into a single dependency graph.
  • Runnable services live in apps/, including the React web UI, admin console, live export service, and the Python Django api.
  • Shared code resides in packages/, exposing scoped modules like @plane/ui, @plane/types, and @plane/utils to any app via workspace:* imports.
  • The Python API is explicitly excluded from the Node workspace, preventing tooling conflicts while maintaining monorepo colocation.
  • Turbo, Vite, and Docker Compose coordinate builds and local development across the polyglot stack.

Frequently Asked Questions

Why does Plane use a monorepo instead of separate repositories?

The monorepo structure ensures that changes to shared type definitions in packages/types/ immediately propagate to both the web and admin apps, preventing API contract mismatches. It also centralizes tooling configuration—updates to OxLint or Vite versions apply project-wide through the pnpm-workspace.yaml catalog, reducing maintenance overhead across the codebase.

How does the Python API coexist with the Node.js applications?

The apps/api/ directory contains a standard Django project that operates outside the pnpm workspace, as specified by the !apps/api exclusion in pnpm-workspace.yaml. This isolation allows the Python environment to manage its own dependencies via requirements.txt while remaining colocated for Docker Compose orchestration and version control simplicity.

What is the purpose of the packages/ directory?

The packages/ directory contains reusable libraries that enforce design consistency and reduce duplication. For example, @plane/ui centralizes Tailwind component styling, while @plane/utils houses cross-cutting logic like URL builders. Any app can import these using workspace:* specifiers, ensuring a single source of truth for utilities without publishing to npm registries.

How do I add a new shared package to the workspace?

Create a directory under packages/ with a valid package.json that includes "name": "@plane/your-package". Configure the main and types entry points to point to your src/ directory. Other apps can then import it immediately using import { something } from '@plane/your-package' without additional linking steps, thanks to the apps/* and packages/* glob patterns in pnpm-workspace.yaml.

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 →