Apograph is an Nx monorepo using npm workspaces — not pnpm, not yarn.
apps/
admin/ React 19 + Vite SPA
server/ NestJS API — and your content types
admin-e2e/ Playwright suite for the admin
server-e2e/ Testcontainer + supertest suite for the API
packages/
bootstrap/{admin,server} the two hosts
database/ the connection, the outbox, the unit of work
identity/{domain,server,admin,provider-*} auth, RBAC, API tokens, SSO
content/{domain,server,admin,graphql}
media/{server,admin,provider-*}
transfer/{domain,server,admin}
copilot/{domain,server,admin,provider-*}
cli/ the `apograph` binary
create-apograph-app/ the scaffolder
…This is the monorepo, not a generated app
An app made with npx create-apograph-app has the same four apps/ and no
packages/ — it consumes them from npm. See
installation.
How packages are laid out
A package is either flat — packages/design-system — or grouped by
domain with a runtime split: packages/content/server,
packages/content/admin.
The npm name stays hyphenated regardless of nesting, so packages/bootstrap/admin
publishes as @apograph/bootstrap-admin. The root workspaces globs cover both
shapes.
A group is not limited to admin and server — it holds however many packages
the domain needs, named for what they are. content has four; copilot has six.
Where your code goes
For most projects, the answer is apps/server and nothing else:
| Path | What you put there |
|---|---|
apps/server/src/content/collections/ | One file per collection |
apps/server/src/content/pages/ | One file per single |
apps/server/src/content/index.ts | The registered list, plus table re-exports for drizzle-kit |
apps/server/src/plugins.ts | Which plugins run, and in what order |
apps/server/apograph.config.ts | Per-plugin runtime configuration |
apps/server/migrations/ | Generated SQL for your content tables — committed |
If you are adding a capability rather than content, you are writing a plugin — see extending Apograph.
Commands
npx nx <typecheck|build|lint|test|serve> <project>
npx nx sync # after changing cross-project dependencies
npx nx graph # visualise the project graphRunning the stack
npm run devRuns the whole stack in one terminal, as four tasks in their own Nx panes:
| Task | What it is |
|---|---|
server:dev:build | webpack in watch mode — compile and type errors land here |
server:dev:run | node --watch on the built entry point; Nest logs only |
admin:dev | the Vite dev server, proxying /api to the API |
admin:dev:typecheck | tsc --build --watch, because Vite never typechecks |
That last one matters more than it looks. Vite transpiles without type checking, so without a dedicated pane an admin type error simply does not appear until somebody runs a build.
npm run start:server and npm run start:admin still run either half alone.
Database
docker compose up -d # Postgres 16
npx nx run server:db:migrate # apply every plugin's migrations
npx nx run <plugin>:db:generate --name=<change> # generate one plugin's migration
npx nx run server:db:studio # browse the live databaseThese nx run targets are the monorepo’s — they are inferred by the
@apograph/nx plugin, which is private and never installed in a generated app.
An app scaffolded by create-apograph-app runs the same three operations as
npx apograph migrate, npx apograph generate and npx apograph studio; see the
CLI.
Running several stacks at once
npm run dev is not limited to one checkout. A slot fixes a worktree’s ports
and database — slot n is API :300n, admin :420n, database apograph_cms_an —
so several branches can each hold a live app.
npm run worktree -- provision <slot> --path <worktree>
npm run worktree -- list
npm run worktree -- release <slot> --yesSlots share one Postgres container, because CREATE DATABASE already
isolates the data and five containers do not fit in memory. Two concurrent
stacks is the realistic ceiling on a four-core machine.
Conventions
- Prettier, four-space indent, single quotes.
- Admin i18n is
react-intl, with each component co-locating its owndefineMessagesblock. There is no sharedmessages.ts. - Authoring conventions are encoded as skills under
.agents/skills/—server-plugin,admin-plugin,accessibility,admin-e2e,server-e2e,shadcn. They are written for AI agents but are the most precise description of house style that exists. - Every directory with project-specific context carries an
AGENTS.md, and aCLAUDE.mdthat imports it. EditAGENTS.md; never the importer.
The API reference
A running server documents itself. The generated OpenAPI document is served as an interactive Scalar reference:
http://localhost:3000/reference # the UI
http://localhost:3000/reference/json # the raw documentIt is on outside production. API_DOCS=true publishes it from a deployment;
API_DOCS=false turns it off locally.