Start from a runnable example

Want a head start? Clone cmssy-io/examples - standalone apps for Next.js (simple-blog, next-storefront), Astro and React Router, each with an .env.example pointing at the public demo workspace, so a fresh clone renders real content before you have an account. Point one at your own workspace with npx @cmssy/cli link --token cs_....

Installation

Wire cmssy into a Next.js app with one command, connect it to your workspace, and open it in the editor.

September 20, 2026

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 install

What init writes

Every file is plain code in your repository - open it, change it, there is no hidden runtime behind it:

FileWhat it does
cmssy.config.tsReads server env and validates it at startup. Server-only: never import a value from it in a client component.
proxy.tsResolves the language, rewrites verified editor traffic to /cmssy-edit, applies the CSP that lets the admin frame the site.
services/pages.tsYour delivery queries, in your repo. generateStaticParams lives here.
cmssy/blocks.tsThe block registry - the server renders from this list, the editor loads it lazily.
cmssy/editor.tsx, cmssy/editable-layout.tsx, cmssy/site-providers.tsxEditor 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.tsDraft-mode entry for the editor, and the on-publish revalidation webhook.
.env.exampleThe 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

VariableWhat it isWhere it comes from
CMSSY_ORG_SLUGYour organization slugcmssy link (Settings → Headless)
CMSSY_WORKSPACE_SLUGYour workspace slug - resolves the workspacecmssy link (Settings → Headless)
CMSSY_DRAFT_SECRETSecret the editor proves itself with to enter draft / preview modecmssy link (Settings → Headless)
CMSSY_WEBHOOK_SECRETSigning secret of the content.changed webhook pointed at /api/revalidateSettings → Webhooks - needed on the deployed site, not by the dev server
CMSSY_API_URLGraphQL delivery endpoint. Defaults to https://api.cmssy.io/graphqlSelf-host / staging only
CMSSY_EDITOR_ORIGINAdmin origin that frames your site. Defaults to https://www.cmssy.ioSelf-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:3000

Open 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 watches

Updating 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 version

Wiring 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.ts or 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 set CMSSY_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_ORIGIN must be your admin origin.
  • Blank page - CMSSY_WORKSPACE_SLUG must match your workspace (and, if self-hosting, CMSSY_API_URL must be the full GraphQL endpoint).
  • "Port 3000 already in use" - stop other dev servers or run next dev -p 3001 and point the Dev host at that port.
  • Node.js version error - upgrade to Node.js 20+ with nvm install 20.

Next steps