Installation
Wire cmssy into a Next.js app with one command, connect it to your workspace, and open it in the editor.
Prerequisites
- Node.js 20+ - we recommend nvm
- pnpm - npm, yarn and bun work too; the CLI prints the install command that matches your lockfile
- A cmssy workspace and an API token - create the token under Settings → API Tokens; it is what connects the app to the workspace
- A Next.js App Router app, new or existing. The CLI also wires Astro and React Router 7 apps - the files differ, the steps below do not.
Create the app and wire cmssy
Scaffold a Next.js app (or cd into the one you have), then let the CLI wire it. cmssy init detects the framework, copies the wiring files into your repo, adds @cmssy/next, @cmssy/react and @cmssy/core to package.json, and prints every file it wrote with a line on what it is for.
npx create-next-app@latest my-site # App Router: yes
cd my-site
npx @cmssy/cli@latest init
pnpm installWhat init writes
Every file is plain code in your repository - open it, change it, there is no hidden runtime behind it:
| File | What it does |
|---|---|
cmssy.config.ts | Reads server env and validates it at startup. Server-only: never import a value from it in a client component. |
proxy.ts | Resolves the language, rewrites verified editor traffic to /cmssy-edit, applies the CSP that lets the admin frame the site. |
services/pages.ts | Your delivery queries, in your repo. generateStaticParams lives here. |
cmssy/blocks.ts | The block registry - the server renders from this list, the editor loads it lazily. |
cmssy/editor.tsx, cmssy/editable-layout.tsx, cmssy/site-providers.tsx | Editor bootstrap, header and footer through the edit bridge, and the one place your own providers go. |
blocks/hero/ | An example block: the schema beside the component that reads it. |
app/[[...path]]/, app/cmssy-edit/[[...path]]/ | Page and layout for the site and for the framed editor. These are the root layouts, so the app has no app/layout.tsx. |
app/api/draft/route.ts, app/api/revalidate/route.ts | Draft-mode entry for the editor, and the on-publish revalidation webhook. |
.env.example | The variables the config reads. |
Files that already exist are skipped and listed; --force overwrites them. Under src/ when the app uses one. When the app lints and has no config of its own, init also drops an eslint.config.mjs with the cmssy plugin. The full description of each file is on the CLI page.
Connect the app to your workspace
cmssy link writes CMSSY_ORG_SLUG, CMSSY_WORKSPACE_SLUG and CMSSY_DRAFT_SECRET into .env.local and verifies them against the API, so a typo fails here and not on the first render.
npx @cmssy/cli@latest link --token cs_...Without --token the CLI reads CMSSY_API_TOKEN. A token from a user with several workspaces gets asked which one; --workspace <slug> skips the question.
The environment, in one place
| Variable | What it is | Where it comes from |
|---|---|---|
CMSSY_ORG_SLUG | Your organization slug | cmssy link (Settings → Headless) |
CMSSY_WORKSPACE_SLUG | Your workspace slug - resolves the workspace | cmssy link (Settings → Headless) |
CMSSY_DRAFT_SECRET | Secret the editor proves itself with to enter draft / preview mode | cmssy link (Settings → Headless) |
CMSSY_WEBHOOK_SECRET | Signing secret of the content.changed webhook pointed at /api/revalidate | Settings → Webhooks - needed on the deployed site, not by the dev server |
CMSSY_API_URL | GraphQL delivery endpoint. Defaults to https://api.cmssy.io/graphql | Self-host / staging only |
CMSSY_EDITOR_ORIGIN | Admin origin that frames your site. Defaults to https://www.cmssy.io | Self-host only |
cmssy.config.ts passes them to defineCmssyConfig raw. It validates at startup and names any variable you are missing - a ?? "" fallback would hide that, and the error would surface later, somewhere unrelated.
import { defineCmssyConfig } from "@cmssy/next";
export const cmssy = defineCmssyConfig({
org: process.env.CMSSY_ORG_SLUG,
workspaceSlug: process.env.CMSSY_WORKSPACE_SLUG,
draftSecret: process.env.CMSSY_DRAFT_SECRET,
});Keep .env.local out of version control. In production, set the same variables in your hosting provider (e.g. the Vercel project settings).
Start development
pnpm dev # http://localhost:3000Open http://localhost:3000 - the app renders the published pages of your workspace with the blocks in cmssy/blocks.ts.
Editor preview
The editor frames your site in an iframe and edits it live. The draft route and the CSP in proxy.ts are already in place from init; what you point at your site is one setting:
- While developing, enable the Dev host in the editor with
http://localhost:3000. That target is yours only and touches nothing shared. - For the deployed site, set the workspace Preview URL (Settings → Headless) - e.g.
https://your-site.com.
On cmssy cloud the editor origin is configured for you. If you self-host the admin, set CMSSY_EDITOR_ORIGIN to your admin origin - the SDK uses it for the postMessage bridge and for the CSP frame-ancestors that lets the admin frame your site.
Deploy
Deploy like any Next.js app. Set the same environment variables in your host, including CMSSY_WEBHOOK_SECRET, point the content.changed webhook at https://your-site.com/api/revalidate so a publish shows up without a redeploy, and set the workspace Preview URL to the deployed site.
vercel # or push to the Git repo your host watchesUpdating the SDK
Bump the @cmssy/* packages together - @cmssy/next peer-depends on a matching @cmssy/react and @cmssy/core. The CLI is not installed; npx @cmssy/cli@latest always runs the current one.
pnpm up @cmssy/next @cmssy/react @cmssy/core
pnpm why @cmssy/react # check the installed versionWiring by hand
init is a file copier, nothing more. If you would rather add the files yourself, or want to read what each one does before trusting it, the per-framework layout is described under Rendering and the CLI page lists every file init writes, for Next.js, Astro and React Router.
Troubleshooting
- init says a file exists, skipped - the app already had it (usually
proxy.tsor a root layout). init never overwrites without--force; diff yours against the file init would write and merge by hand. - link: "no API token given" - pass
--token cs_...or setCMSSY_API_TOKEN. The token comes from Settings → API Tokens. - "Preview didn't connect" - the Dev host or the workspace Preview URL must point at the running site. If you self-host the admin,
CMSSY_EDITOR_ORIGINmust be your admin origin. - Blank page -
CMSSY_WORKSPACE_SLUGmust match your workspace (and, if self-hosting,CMSSY_API_URLmust be the full GraphQL endpoint). - "Port 3000 already in use" - stop other dev servers or run
next dev -p 3001and point the Dev host at that port. - Node.js version error - upgrade to Node.js 20+ with
nvm install 20.
Next steps
- Your first block, live - from this setup to a block you wrote, edited in the editor and published
- Block Development - block anatomy, schemas and field types
- Page Builder - editing content in the visual editor