---
title: "Plane Architecture Overview"
description: "Plane's three-tier architecture — database, API, frontend, state management, and real-time services"
image: "https://tractiongrowth.com/og/open-source/plane-project-management/architecture/image.png"
---

# Plane Architecture Overview

# Plane Architecture Overview

<Callout title="For Product Managers">
  This page explains *how Plane is structured* as a software system. You don't need to understand every technical detail — focus on the diagrams and the "Why It Matters" callouts to build a mental model of how the product works under the hood.
</Callout>

Plane uses a three-tier architecture with React applications for the UI, a Django and DRF backend for business logic, PostgreSQL and supporting services for persistence, and Hocuspocus plus Celery for collaboration and background work. This page breaks down how those layers fit together and why that structure supports self-hosting, real-time editing, and product complexity.

## How Plane's Architecture Works

Plane follows a **three-tier architecture** with a real-time collaboration layer, served through a Caddy reverse proxy:

```
┌─────────────────────────────────────────────────────────────────┐
│                         USERS (Browser)                         │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                    ┌──────────▼──────────┐
                    │  Caddy Proxy (2.10)  │  ← automatic HTTPS
                    │  Port 80 / 443       │    routes by path
                    └──┬──────┬───────┬───┘
                       │      │       │
       ┌───────────────▼─┐ ┌──▼─────┐ ┌▼───────────────┐
       │  Web / Admin /   │ │  API   │ │  Live Server    │
       │  Space (React)   │ │(Django │ │ (Hocuspocus)    │
       │  Nginx           │ │ DRF)   │ │ WebSocket CRDT  │
       │  :3000/3001/3002 │ │ :8000  │ │ :3100           │
       └──────────────────┘ └──┬─────┘ └─────────────────┘
                               │
              ┌────────────────┼────────────────┐
              │                │                │
       ┌──────▼──────┐ ┌──────▼──────┐ ┌───────▼───────┐
       │ PostgreSQL   │ │   Valkey    │ │  MinIO / S3   │
       │   15.7       │ │   7.2.11    │ │ (File Storage)│
       │ (Primary DB) │ │ (Cache)     │ │               │
       └──────────────┘ └─────────────┘ └───────────────┘
                               │
                        ┌──────▼──────┐
                        │  RabbitMQ   │
                        │   3.13.6    │
                        │ (MQ Broker) │
                        └──────┬──────┘
                               │
                        ┌──────▼──────┐
                        │   Celery    │
                        │  Workers    │
                        │  + Beat     │
                        └─────────────┘
```

<Callout type="info" title="Why It Matters">
  Every user request flows through Caddy → the appropriate service. REST API calls hit Django; real-time editing uses WebSockets to the Hocuspocus live server. Background work (email notifications, cleanup, imports) runs through Celery workers using **RabbitMQ** as the message broker. Valkey (Redis-compatible) handles caching and sessions. This separation means the API stays fast even when heavy async work is running.
</Callout>

## The Three Tiers

### 1. Frontend Layer (React 18 + MobX)

The frontend is built with **React 18**, **React Router 7** (with SSR support), and **MobX** for state management. Three separate apps share packages:

| App       | Port | Purpose                                              |
| --------- | ---- | ---------------------------------------------------- |
| **web**   | 3000 | Main user-facing application (issues, boards, pages) |
| **admin** | 3001 | Instance administration (`/god-mode/`)               |
| **space** | 3002 | Public-facing project views (shareable links)        |

**MobX Store Hierarchy (180+ files):**

```
RootStore
  ├── router.store           → routing state
  ├── theme.store             → UI theme
  ├── instance.store          → instance config
  ├── user/
  │     ├── profile.store     → current user
  │     ├── account.store     → auth account
  │     └── settings.store    → user preferences
  ├── workspace/
  │     ├── index.ts          → workspace data
  │     ├── home.ts           → home dashboard
  │     ├── webhook.store     → webhook management
  │     └── api-token.store   → API tokens
  ├── project/
  │     ├── project.store     → project CRUD
  │     └── project_filter    → view filters
  ├── issue/                  → issue stores per context
  │     ├── project/          → project issue list
  │     ├── cycle/            → cycle issues
  │     ├── module/           → module issues
  │     └── workspace-draft/  → draft issues
  ├── pages/                  → wiki pages
  ├── notifications/          → notification center
  ├── timeline/               → activity timeline
  └── ...
```

<Callout type="info" title="Why MobX + SWR?">
  MobX provides *fine-grained reactivity*: when a single issue's title changes, only the components rendering that title re-render. SWR complements MobX by handling data fetching and cache invalidation. MobX stores hold the canonical state; SWR fetches and revalidates from the API.
</Callout>

### 2. API Layer (Django 4.2 + DRF)

The backend is **Django 4.2.29 LTS** with **Django REST Framework 3.15.2**, living at `apps/api/`.

**URL Routing Structure:**

```
/api/             → plane.app.urls       (main app — workspaces, projects, issues)
/api/public/      → plane.space.urls     (public/anonymous endpoints)
/api/instances/   → plane.license.urls   (instance management)
/api/v1/          → plane.api.urls       (API key–based access)
/auth/            → plane.authentication (login, OAuth, magic links)
```

**App-level URL modules (20+):**

```
plane/app/urls/
  ├── analytic.py, api.py, asset.py, cycle.py, estimate.py
  ├── external.py, intake.py, issue.py, module.py, notification.py
  ├── page.py, project.py, search.py, state.py, user.py
  ├── views.py, webhook.py, workspace.py, timezone.py, exporter.py
```

**Key API Patterns:**

| Pattern                   | Description                                      |
| ------------------------- | ------------------------------------------------ |
| **Hierarchical URLs**     | Workspaces → Projects → Issues/Cycles/Modules    |
| **Standard REST**         | GET, POST, PATCH, DELETE                         |
| **Throttling**            | 30/min anon, 60/min API key, custom per-endpoint |
| **Serializer validation** | DRF serializers validate all input/output        |
| **API documentation**     | drf-spectacular (OpenAPI/Swagger)                |

### 3. Database Layer (PostgreSQL 15.7)

PostgreSQL with **30+ model files** and **126 migrations**.

**Core Entity-Relationship Map:**

```
                         ┌──────────────┐
                         │   Workspace  │ ← multi-tenancy root
                         └──────┬───────┘
                                │ has many
                    ┌───────────┼───────────┐
                    │           │           │
             ┌──────▼──────┐   │    ┌──────▼──────┐
             │   Project    │   │    │   Member    │
             └──────┬───────┘   │    └─────────────┘
                    │           │
         ┌──────────┼──────┬───┼──────┐
         │          │      │   │      │
   ┌─────▼────┐ ┌──▼───┐ ┌▼───▼─┐ ┌──▼─────┐
   │  Issue    │ │Cycle │ │Module│ │ State  │
   │ (central)│ │      │ │      │ │        │
   └────┬─────┘ └──┬───┘ └──┬───┘ └────────┘
        │          │        │
        │    CycleIssue  ModuleIssue
        │      (M2M)       (M2M)
        │
   ┌────┼────┬──────────┬─────────┐
   │    │    │          │         │
 Comment Activity  Reaction  Attachment
```

**Base Model Pattern — all workspace models inherit:**

| Field        | Purpose                               |
| ------------ | ------------------------------------- |
| `id`         | UUID primary key                      |
| `created_at` | Auto-set on creation                  |
| `updated_at` | Auto-set on every save                |
| `created_by` | Foreign key to User                   |
| `updated_by` | Foreign key to User                   |
| `deleted_at` | Soft-delete timestamp (null = active) |
| `workspace`  | Foreign key enforcing multi-tenancy   |

## Key Design Patterns

### Multi-Tenancy

Every query is scoped to a workspace — enforced at the view level so no data leaks between organizations.

### Soft Deletion

Records are never physically deleted. `deleted_at` is set, and a daily Celery beat task permanently removes records older than `HARD_DELETE_AFTER_DAYS`.

### Activity Audit Trail

Every change to an Issue generates an `IssueActivity` record tracking what changed, who changed it, and when.

### Community / Enterprise Gating

The web app has `ce/` (community edition) and `ee/` (enterprise edition) directories, enabling feature gating between the free and paid versions.

## Real-Time Collaboration

The **Live server** (`apps/live/`) runs Hocuspocus on port 3100:

| Component          | Technology                             |
| ------------------ | -------------------------------------- |
| **Server**         | Hocuspocus 2.15.2 (Node.js)            |
| **CRDT**           | Yjs 13.6.20                            |
| **Editor binding** | y-prosemirror (Yjs ↔ ProseMirror)      |
| **Persistence**    | @hocuspocus/extension-database + Redis |
| **Transport**      | WebSocket via express-ws               |

When users edit Pages collaboratively, the Hocuspocus server merges their changes using CRDT math, persists to the database, and broadcasts updates to all connected clients.

## Performance Architecture

### Database

* Indexes on frequently queried fields (workspace\_id, project\_id, state\_id)
* Read replica support for horizontal scaling

### API

* Valkey caching for frequently accessed data
* Throttling at multiple levels (anon, API key, asset, email verification)
* GZip middleware for response compression

### Frontend

* MobX computed values — derived state only recalculates when dependencies change
* Code splitting — lazy-loaded routes via React Router
* SWR caching — stale-while-revalidate pattern for API data

## What's Next

<Cards>
  <Card title="What Is Plane?" description="Product overview, target users, differentiators, and core concepts." href="/open-source/plane-project-management" />

  <Card title="Plane Workflows and Data Flows" description="Trace key user journeys through all three tiers." href="/open-source/plane-project-management/workflows" />

  <Card title="How Plane Is Built" description="Repository structure, build pipeline, and deployment." href="/open-source/plane-project-management/how-it-is-built" />
</Cards>

