Skip to content

Notion#

Problem statement (interviewer prompt)

Design Notion: a block-based collaborative document + wiki + lightweight database (tables, kanban, calendar). Each block is a tree node, multiple users edit concurrently, and pages can reference other pages. Support offline edit + sync, permissions, and full-text search.

flowchart LR
  U([User])
  BLK[Block Service]
  TREE[(Block tree per page)]
  DB[Database / View]
  PG[Page Renderer]
  U --> BLK --> TREE
  BLK --> DB
  TREE --> PG --> U

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class U client;
    class BLK,PG service;
    class TREE,DB datastore;
flowchart TB
  subgraph Clients
    WEB
    MOB
    DESK[Desktop]
  end

  subgraph Edge
    LB
    WS[WebSocket gateway]
  end

  subgraph Core
    BLK[Block Service<br/>everything is a block]
    PARENT[Tree maintenance<br/>parent / children pointers]
    DBV[Database / View Service<br/>tables, kanban, calendar]
    PROPS[Property types]
    PERMS[Permissions inherited from parent]
  end

  subgraph Sync[Sync engine]
    REC[Record transactions]
    QU[[Per-record ops queue]]
    OFFLINE[Offline ops]
    SYNC([Sync engine reconcile])
  end

  subgraph Storage
    PG[(Postgres - blocks as rows)]
    META[(Workspace metadata)]
    FILES[(Files / S3)]
    SEARCH[(Search index)]
  end

  subgraph Features
    COMM[Comments / mentions]
    REM[Reminders / notifications]
    TPL[Templates]
    AI[Notion AI]
    SYNCED[Synced blocks across pages]
  end

  Clients --> Edge --> Core --> Storage
  Sync --- Core
  Features --- Core

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class WS edge;
    class DESK,BLK,PARENT,PROPS,PERMS,REC,OFFLINE,COMM,REM,TPL,AI,SYNCED service;
    class DBV,PG,META,SEARCH datastore;
    class QU queue;
    class SYNC compute;
    class FILES storage;

Block model#

  • Everything (page, paragraph, todo, image, db) is a block with id, parent_id, type, properties, content[].
  • Tree edits cascade in deterministic order; permissions inherited.

Sync engine#

  • Optimistic local writes; reconciliation on sync.
  • Conflict resolution mostly LWW per property; tree structure uses parent-aware merge.

Glossary & fundamentals#

Concepts referenced in this design. Each row links to its canonical page; the tag column shows whether it is a high-level (HLD) or low-level (LLD) concept.

Tag Concept What it is Page
HLD Realtime protocols WS / SSE / polling / gRPC streaming realtime-protocols

Quick reference#

Functional#

  • Block-based pages with rich content.
  • Inline databases with multiple views.
  • Real-time multi-user editing.
  • Comments, mentions, reminders.
  • Offline support.
  • AI / search.

Non-functional#

  • p99 sync < 1 s.
  • Workspaces up to 10s of thousands of users.
  • Offline editing must reconcile cleanly.

Trade-offs#

  • Block as universal primitive = expressive but verbose.
  • Postgres at scale demands sharding (workspace).
  • Tree with permissions inheritance: change at parent cascades.

Refs#

  • Notion engineering blog ("Sharding our Postgres", "Building Notion AI").
  • ByteByteGo "Design Notion".

FAQ#

How does Notion store documents?#

Every page is a tree of blocks where each block is a row in a relational store with parent_id, type, and properties. Rendering walks the tree and resolves block references on the fly.

What is the block model in Notion?#

A block is a small typed unit (paragraph, heading, todo, table row, embed). Pages, databases, and views are all built from the same block primitive linked by parent and child references.

How does Notion handle real-time collaboration?#

Block edits are streamed over WebSocket and applied with last-write-wins per property. Concurrent edits on different properties of the same block compose cleanly without a merge UI.

How does Notion implement databases and views?#

A database is a block whose children are entry blocks. A view is metadata pointing at the database with filter, sort, group, and layout (table, kanban, calendar) interpreted at render time.

How does Notion handle offline editing?#

Clients keep a local cache of recently viewed blocks and queue edits with a logical clock. On reconnect they replay against the server, which dedupes by op id and applies in order.