Features Apograph CMS on GitHub

Installation

Prerequisites, the two ways in, first boot, and upgrading afterwards.

Documents 0.5.2 Updated Edit this page Report a problem

On this page

Two ways in. Scaffold an app that consumes the packages from npm, or clone the monorepo and work on Apograph itself.

Almost everybody wants the first.

Prerequisites

VersionWhy
Node22 or newerThe CLI uses process.loadEnvFile and node --watch
PostgreSQL16The only supported database; the compose file and every deployment guide run 16
npm10 or newerExact-pinned dependencies, no workspaces in a generated app

A docker-compose.yml in the monorepo brings up a Postgres if you do not have one.

Scaffolding an app

npx create-apograph-app my-cms
cd my-cms

The wizard’s four questions are covered in the CLI reference. Every one has a default, and --yes takes all of them.

What you get

my-cms/
├── package.json          one package — not workspaces
├── tsconfig.json         references the four apps
└── apps/
    ├── server/           apograph.config.ts, src/{main,plugins}.ts
    ├── admin/            index.html, vite.config.mts, src/
    ├── server-e2e/       jest + supertest, against a real Postgres
    └── admin-e2e/        Playwright, with /api mocked

The same four apps Apograph itself is built from, so anyone who has read the source finds the same shape in their project.

One package.json, deliberately

npm workspaces would let the server and admin halves resolve different copies of a shared package — two @apograph/design-system instances means two React contexts and a UI that silently stops talking to itself.

A scaffolded app ships a working test setup: Jest for the server (NestJS needs emitDecoratorMetadata, which Vitest’s transform does not emit), Vitest for the admin, and the two end-to-end suites. A starter that cannot be tested teaches people not to.

Configure

cp .env.example .env

DATABASE_URL is the only variable the app refuses to load without. Set APOGRAPH_ROOT_ADMIN_EMAIL and APOGRAPH_ROOT_ADMIN_PASSWORD too, or you will have a CMS with no way in.

Every other variable is optional and documented in configuration.

Migrate and boot

npx apograph migrate
npx apograph dev

migrate builds the server and applies every plugin’s migrations in plugin order. dev runs the API and the admin dev server together.

For a deployment, apograph build then apograph start — one process serves the API and the built admin from one origin, which is what identity’s SameSite=lax session cookie needs.

Verifying the install

The API reference is served on /reference outside production, generated from the running app rather than written by hand. If your content type is in it, the registry loaded and the routes are mounted.

Set API_DOCS=true to publish it from a deployed instance.

Upgrading

Every @apograph/* package is released in lockstep, pinned exactly, with no caret.

npm install @apograph/content-server@0.5.2 @apograph/content-admin@0.5.2 # …and the rest
npx apograph migrate

Upgrade the whole set, or none of it

A partial upgrade can leave two copies of a shared package in node_modules — two React context instances, and an admin whose sidebar silently stops talking to its provider.

Nothing errors. The UI simply stops working in a way that looks like a bug in your own code.

Run apograph migrate after every upgrade. A release that adds a table ships its migration in the plugin that owns it.

Working on Apograph itself

git clone https://github.com/apograph-source/apograph-cms
cd apograph-cms
npm install
cp .env.example .env
docker compose up -d
npx nx run server:db:migrate
npm run dev

The monorepo resolves every package from source, so a change in a package is live in the app without a build step. Its Nx targets are thin adapters over the same functions the apograph binary exposes — one implementation of “apply migrations in plugin order”, because two would be two chances to get the most destructive operation in the system wrong.

See project structure for the layout.