Installation
Set up a new CMS project from scratch.
Prerequisites
- Node.js 20+ (or Bun)
- Postgres 15+
- pnpm (recommended) or npm
Quick start
Install the CMS packages in your project:
pnpm add @cms/engine @cms/config
Create a cms.config.ts at your project root:
import { config, entity, text, slug, select, role } from "@cms/config";
const posts = entity("posts", {
fields: [
text("title", { required: true }),
slug("slug", { unique: true, required: true }),
select("status", { options: ["draft", "published"] }),
],
});
const admin = role("admin", { isAdmin: true });
export default config({
entities: [posts],
roles: [admin],
});
Set up your environment:
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/cms
PORT=3000
ADMIN_UI=true
CMS_CONFIG_PATH=./cms.config.ts
Environment variables
| Variable | Default | Description |
|---|---|---|
| DATABASE_URL | — | Postgres connection string (required) |
| PORT | 3000 | Server port |
| ADMIN_UI | true | Serve admin UI at /admin. Set false for headless-only |
| CMS_CONFIG_PATH | — | Path to your cms.config.ts file |
| CMS_SEED_ADMIN_EMAIL | admin@cms.local | Email used for the seeded admin user. Only used when _user is empty. Auth is OTP-only — no password |
| LOG_LEVEL | info | Pino log level (debug, info, warn, error) |
| MIGRATIONS_PATH | ./migrations | Directory for migration files |
Dev mode vs production
In development, run cms migration push to sync the database schema directly from your config — no migration files. Convenient while iterating; accepts data loss.
In production, generate and commit migration files, then apply them as a pre-deploy step. cms start never auto-runs migrations.
Generate and apply migrations
# Generate the initial migration from your config
cms migration generate initial
# Apply pending migrations
cms migration apply
See the CMS CLI reference for the full command list.
Start the server
cms dev
The API is available at http://localhost:3000/api and the admin UI at http://localhost:3000/admin.
On first boot with an empty _user table, CMS creates a default admin user and logs the credentials to the console.
Previous
Introduction
Next
Configuration