Skip to content

Architecture Overview

How the InlineCMS monorepo is structured and how the pieces fit together.

packages/
types/ Shared TypeScript interfaces — the system contract
core/ InlineCMSClient, ContentStore, ComponentRegistry, AuthManager
react/ InlineCMSProvider, useCMS, useAuth, InlineElements, withCMS, CMSToolbar
vue/ InlineCMSPlugin, useCMS, useAuth, CMSField, defineInlineComponent
vite-plugin/ Build-time JSX transform + SHA1 fingerprint injection
babel-plugin/ Same transform for non-Vite toolchains
apps/
api/ Hono API + Drizzle ORM + PostgreSQL
dashboard/ React management UI
docs/ Starlight documentation (this site)
demo/ Demo app for testing the SDK
docker/
Dockerfile Multi-stage production build
docker-compose Self-hosted setup with PostgreSQL

Handles all HTTP. Routes content fetches to CDN for visitors and directly to the API for editors (bypassing cache so they always see drafts).

Tracks every mounted CMS component on the page. Debounced sync to the backend (300ms) prevents request floods during initial render.

In-memory cache of field values with optimistic local updates. setField() writes locally immediately; persistence is async. Re-fetches content after login and after component sync.

CMS session lifecycle. Persists to sessionStorage (survives page refresh, cleared on tab close). Notifies subscribers on login/logout.

Editor publishes
→ API saves to PostgreSQL (status: published)
→ CDN cache invalidated via webhook
→ Content history record written (audit trail)
Visitor request
→ CDN edge (~5ms)
→ Cache miss → API → PostgreSQL
→ Response cached at edge
Editor request
→ API directly (bypass CDN)
→ Returns drafts + published

Editors are invited into a project and authenticate with InlineCMS directly (email + password, Argon2-hashed, JWT session). Each editor has a role (admin / editor / viewer) and, optionally, a set of allowedPaths that scopes which page URLs they may edit (glob wildcards supported, e.g. /blog/*).

To edit a live page, an editor signs into the admin and “enables editing” on a site, which mints a short-lived, single-use, origin-bound handoff token that the page redeems for an editor session. InlineCMS does not integrate with or depend on the host application’s own user system.

Core tables, managed by Drizzle ORM:

TablePurpose
organizationsOptional ownership grouping above projects (tenancy seam)
projectsTop-level tenant with API key and domains
cms_usersEditor accounts with roles + optional URL scoping
sessionsServer-side JWT tracking for invalidation
handoff_tokensSingle-use, origin-bound tokens for live-page editor access
pagesRegistered pages (path + title)
component_definitionsField schemas registered by the SDK
content_entriesActual content (draft/published/archived)
content_historyImmutable publish audit trail
mediaUploaded files
Was this page helpful? Your feedback goes straight to the docs team.