Plane
How Plane Is Built Repository structure, build system, dependencies, deployment pipeline, and developer experience
This page covers the practical side of Plane's engineering: how the repository is organized, how the build system works, what dependencies are used, and how the product gets deployed.
For Product Managers
This page answers "how does the engineering team ship Plane?" — the tools, processes, and infrastructure that turn source code into a running product. Understanding this helps you grasp engineering timelines, deployment complexity, and maintenance costs.
Plane is a pnpm monorepo with Turborepo for build orchestration. All applications and shared packages live in a single Git repository.
plane/
├── apps/
│ ├── web/ ← React SPA — main user interface (port 3000)
│ ├── admin/ ← Admin panel — instance settings (port 3001)
│ ├── space/ ← Public project views — shareable (port 3002)
│ ├── api/ ← Django REST API — all business logic
│ ├── live/ ← Hocuspocus — real-time CRDT server (port 3100)
│ └── proxy/ ← Caddy reverse proxy
├── packages/
│ ├── ui/ ← 84 reusable React components
│ ├── editor/ ← Tiptap/Yjs rich text editor
│ ├── types/ ← 117 TypeScript type definition files
│ ├── constants/ ← Shared enums and config
│ ├── services/ ← API service layer (Axios wrappers)
│ ├── hooks/ ← Shared React hooks
│ ├── shared-state/ ← Shared MobX stores (user, workspace, filters)
│ ├── i18n/ ← Internationalization (20 languages)
│ ├── propel/ ← UI primitives (accordion, charts, combobox)
│ ├── utils/ ← Helper utilities (date, sanitize, markdown)
│ ├── logger/ ← Winston-based logging
│ ├── decorators/ ← Express controller/route decorators
│ ├── tailwind-config/← Shared Tailwind 4.1 configuration
│ ├── typescript-config/ ← Shared TypeScript configs
│ └── codemods/ ← JSCodeshift migration scripts
├── deployments/
│ ├── cli/ ← Docker Compose self-hosted CLI
│ ├── kubernetes/ ← K8s manifests (community maintained)
│ └── aio/ ← All-in-One single container
├── turbo.json ← Turborepo task configuration
├── pnpm-workspace.yaml ← Workspace package definitions
└── package.json ← Root config (pnpm 10.30, Node ≥22.18)
App Technology Purpose web React 18 + React Router 7 + Vite Main user-facing application (1,482 TSX files) admin React 18 + React Router 7 + Vite Instance administration (/god-mode/) space React 18 + React Router 7 + Vite (SSR) Public-facing project views (shareable links) api Django 4.2.29 + DRF 3.15.2 REST API, business logic, database management live Node.js + Hocuspocus 2.15.2 Real-time collaborative editing WebSocket server proxy Caddy 2.10 Reverse proxy with automatic HTTPS
Package Purpose @plane/ui84 reusable UI components (buttons, modals, dropdowns, tables) @plane/editorRich text editor (Tiptap + Yjs CRDT collaboration) @plane/types117 TypeScript type definition files (issues, projects, cycles, etc.) @plane/servicesAPI service layer wrapping Axios HTTP calls @plane/hooksShared React hooks @plane/shared-stateShared MobX stores (user, workspace, rich filters) @plane/i18nInternationalization with ICU message format (20 locales) @plane/constantsShared enums, config values @plane/utilsUtility functions (date-fns, sanitize-html, chroma-js) @plane/propelUI primitives (accordion, charts, combobox, switch) @plane/loggerWinston-based structured logging @plane/decoratorsExpress controller/route decorators (for live server) @plane/tailwind-configShared Tailwind CSS 4.1 configuration @plane/typescript-configShared TypeScript configs @plane/codemodsJSCodeshift codemods for code migrations
Why a Monorepo?
All 6 apps share the same types, components, and utilities. When a developer changes an Issue type definition in @plane/types, all apps see the change immediately — no publishing, no version mismatch. Turborepo ensures only affected packages are rebuilt.
pnpm install ← installs all dependencies across workspaces
│
▼
turbo build ← Turborepo orchestrates parallel builds
│
├──► @plane/types (TypeScript → declarations)
├──► @plane/ui (React components → bundled)
├──► @plane/editor (Editor components → bundled)
│
├──► web (react-router build → production bundle)
├──► admin (react-router build → production bundle)
└──► space (react-router build → production bundle)
Each frontend app uses React Router 7 as a framework (with react-router build instead of Vite directly), producing optimized static + server bundles. The production containers serve these via Nginx .
pip install -r requirements/ ← Python dependencies
│
▼
python manage.py migrate ← apply 126 database migrations
│
▼
gunicorn plane.asgi:app ← start production server (ASGI via uvicorn)
Dependency Version Purpose React 18.3.1 UI framework React Router 7.12.0 Client + server routing MobX 6.12.0 Fine-grained reactive state management SWR 2.2.4 Data fetching with stale-while-revalidate caching Tailwind CSS 4.1.17 Utility-first styling Tiptap 2.22.3 Rich text editor (ProseMirror-based) Yjs 13.6.20 CRDT library for real-time collaboration Vite 7.3.1 Build tool and dev server Axios 1.13.5 HTTP client for API calls Recharts ^2.12.7 Charts and data visualization Lucide React 0.469.0 Icon set Headless UI ^1.7.19 Accessible UI primitives TanStack React Table ^8.21.3 Table component React Hook Form 7.51.5 Form management date-fns ^4.1.0 Date utility library
Dependency Version Purpose Django 4.2.29 Web framework (LTS) DRF 3.15.2 REST API framework Celery 5.4.0 Distributed task queue django-celery-beat 2.6.0 Periodic task scheduler psycopg 3.3.0 PostgreSQL 3 driver redis 5.0.4 Redis/Valkey client django-redis 5.4.0 Django cache backend channels 4.1.0 ASGI support gunicorn 23.0.0 Production WSGI/ASGI server uvicorn 0.29.0 ASGI server boto3 1.34.96 AWS S3 / MinIO integration openai 1.63.2 AI features drf-spectacular 0.28.0 OpenAPI/Swagger documentation nh3 (latest) HTML sanitizer (Rust-based) posthog 3.5.0 Product analytics
Service Version Purpose PostgreSQL 15.7-alpine Primary database Valkey 7.2.11-alpine Cache + session store (Redis-compatible) RabbitMQ 3.13.6-management Celery message broker (AMQP) MinIO latest S3-compatible object storage (self-hosted) Caddy 2.10 Reverse proxy with automatic HTTPS Nginx 1.27/1.29-alpine Static frontend serving inside Docker
docker-compose.yml
├── web → React SPA (Nginx)
├── admin → Admin panel (Nginx)
├── space → Public views (Nginx)
├── api → Django API (Gunicorn)
├── worker → Celery worker
├── beat-worker → Celery beat (scheduled tasks)
├── migrator → Runs DB migrations on startup
├── live → Hocuspocus WebSocket server
├── proxy → Caddy reverse proxy
├── plane-db → PostgreSQL 15.7
├── plane-redis → Valkey 7.2.11
├── plane-mq → RabbitMQ 3.13.6
└── plane-minio → MinIO (S3-compatible storage)
Strategy Target Complexity Docker Compose (CLI) Single server Low — one-line install script Kubernetes K8s cluster High — community-maintained manifests All-in-One Single container Lowest — single Docker image with Supervisor Docker Swarm Multi-node Medium — swarm.sh script
# One-line self-hosted install
curl -fsSL https://raw.githubusercontent.com/makeplane/plane/master/deployments/cli/community/install.sh | bash
Layer Tool Scope Backend pytest 9.0.2 Unit, contract, and smoke tests Frontend Vitest Package-level unit tests Visual Storybook + Chromatic Component visual regression Codemods Vitest Migration script testing
Tool Purpose OxLint Fast Rust-based JavaScript/TypeScript linting oxfmt Rust-based code formatting TypeScript strict mode Type safety across all frontend code husky + lint-staged Pre-commit hooks
Tool Purpose PostHog Product analytics and event tracking OpenTelemetry Distributed tracing (Django instrumented) Scout APM Application performance monitoring
# Clone the repository
git clone https://github.com/makeplane/plane.git && cd plane
# Run setup (copies .env, generates secret key, installs deps)
./setup.sh
# Start infrastructure (PostgreSQL, Valkey, RabbitMQ, MinIO)
docker compose -f docker-compose-local.yml up -d
# Start all apps in development
pnpm dev
Task Command Start all apps pnpm devBuild all turbo buildLint turbo check:lintFormat turbo check:formatType check turbo check:typesRun API tests cd apps/api && pytestDB migrations cd apps/api && python manage.py migrateCreate migration cd apps/api && python manage.py makemigrations