The golden path, from an empty folder to a site that reads live content from the platform and is deployed from its repository. Every step says what it writes on your machine and what you see in the dashboard afterwards.
npm create kwisple-site@latest acme-site # pick Astro (recommended) or Next.js
cd acme-site
npx kwisple login # browser opens, approve; no tokens to paste
npx kwisple link # pick agency → client → site (or "+ Nieuwe website"); writes .env
npx kwisple dev # dev server + content model sync + live previewYou need Node 22 or newer, a package manager (pnpm, npm, yarn or bun) and an account on the agency's dashboard with the developer right for the client (ask the agency to add you to its team if kwisple link says you have no clients to link).
The packages (
@kwisple/sdk,@kwisple/cms,create-kwisple-site) are prepared for npm but not published yet. Inside the platform monorepo you create a site withpnpm create-site ../acme-site: it packs the local packages into the project'svendor/folder and installs them from there (pnpm only). Commitvendor/until the packages are on npm.
Step 1: create the project
npm create kwisple-site@latest acme-siteWithout flags the CLI asks four questions: where to create the site (default mijn-site), which framework (Astro (aanbevolen) or Next.js), which package manager (the one that started the command is pre-selected) and whether to start with content (Leeg, Dienstverlener or Horeca). Flags skip the questions:
| Flag | Meaning |
|---|---|
--framework astro|next (also --astro, --next, -f, --template, -t) | The starter to copy. Default astro. |
--pm pnpm|npm|yarn|bun | Package manager. Default: the one running the command. |
--kit dienstverlener|horeca|geen | Starting content, copied to cms/seed.json for kwisple seed. |
--install / --no-install | Run the install right away. |
--no-git | Do not run git init. |
-y, --yes | No questions: defaults for anything missing. |
What it does: copies the starter (without build output, .env files or editor state), gives package.json your folder's name, replaces workspace:* dependencies with released versions, writes pnpm-workspace.yaml when you use pnpm, runs git init -b main unless the folder is already inside a repository, and prints the next steps. kwisple create [dir] is the same command once the SDK is installed.
Step 2: log in from the terminal
npx kwisple loginThis is a device flow (RFC 8628). The terminal shows a code like WDJB-MJHT and opens the dashboard's /cli page, titled Terminal koppelen (connect terminal). The page asks Geef de CLI toegang? (give the CLI access?) and shows the code, your device name (for example MacBook-Robbe · macOS) and who you are signed in as. Check that the code matches and click Toegang geven (give access).
What it writes: a personal CLI token in ~/.config/kwisple/credentials.json (mode 0600; KWISPLE_CONFIG_DIR overrides the folder). The token is never printed. The CLI polls until you approve; a code lives ten minutes.
What you see in the dashboard: under Instellingen → Koppelingen → Terminal the entry for your machine, where you (or the agency) can revoke it. kwisple whoami shows who the CLI is signed in as; kwisple logout revokes the token and forgets it.
Which dashboard the CLI talks to: --dashboard <url>, else KWISPLE_DASHBOARD_URL, else the project's KWISPLE_DASHBOARD_ORIGIN from .env, else your last login, else https://app.kwisple.com. Against a local platform pass --dashboard http://localhost:4100. White-label agencies log in on their own dashboard host.
Step 3: link the project to a website
npx kwisple linkAn interactive picker (arrow keys): Bureau (agency, only when you belong to more than one), Klant (client) and Website. The list only shows clients where you may link a site. Choose an existing custom-code site, or + Nieuwe website to create one with a name (default: your folder name). Hosted and external sites cannot be linked (Deze website is niet op maat gebouwd).
Non-interactive variants: kwisple link --site <id|slug>, or kwisple link --client <slug> --name <naam> to create the site first. --preview-url <url> sets a preview URL other than the default.
What it does on the platform:
- creates a site API token with the scopes
read + preview + schema, namedkwisple link · <machine> · <project>; re-linking from the same machine and project replaces it, linking another project never breaks this one; - generates the site's webhook secret when it has none;
- fills in the site's Preview-URL with
http://localhost:<dev port>/api/previewwhen it is still empty (the port comes from yourdevscript:-p 4102for the Next starter,--port 4104for Astro, otherwise 4321 for Astro and 3000 for anything else).
What it writes locally: .env (mode 0600; existing lines and comments are kept, matching keys are replaced, new ones appended under a header # Gekoppeld met kwisple link (<client> · <site>)):
KWISPLE_URL=https://api.kwisple.com
KWISPLE_TOKEN=kwi_…
KWISPLE_WEBHOOK_SECRET=…
KWISPLE_DASHBOARD_ORIGIN=https://app.kwisple.com
KWISPLE_ASSET_ORIGIN=https://assets.kwisple.com
KWISPLE_SITE=<site id>It makes sure .env is in .gitignore (creates or appends) and warns when .env.local also sets one of these keys, because .env.local wins. It prints the site's dashboard link and the preview URL. Every variable is explained in Environment variables and tokens.
What you see in the dashboard: Website → Instellingen → Ontwikkeling (development) now lists your token under API-tokens with the rights Lezen (gepubliceerd), Preview (concepten) and Contentmodel pushen; the Site card shows Preview-URL filled in and a Webhook-geheim.
Step 4: run the dev server with live content
npx kwisple devTwo things start:
- The content model watcher.
cms.config.ts(and everything next to it, such ascms/*.ts) is pushed on every save to the site's development model. Editors and the live site keep using the live model until you promote it withkwisple push. Destructive changes are reported but never auto-applied. - The framework's dev server, started as
<pm> run devwithKWISPLE_SCHEMA=dev, so the SDK reads with the development model (it sendsx-kwisple-schema: dev). Openhttp://localhost:4104(Astro) orhttp://localhost:4102(Next).
Flags: --no-server watches the model only; --live pushes straight to the live model (the older behaviour); --config <pad> uses another config file.
What you see in the dashboard: Instellingen → Ontwikkeling shows Ontwikkelmodel (kwisple dev) (development model) with who pushed it and when, and a Weggooien (discard) button. Under Website the site's pages, sections and globals follow your model. Open an entry, click the live preview: the dashboard opens your local /api/preview, and every autosave refreshes the page in place.
A new site has no content yet. Either add a page in the dashboard, or seed the kit you chose in step 1:
npx kwisple push && npx kwisple seed # model first, then cms/seed.jsonkwisple seed refuses a site that already has content unless --force. Site kits explains the format.
Step 5: your first block
A block is an entry type used inside the page builder's Matrix field. Three edits:
Define it in
cms/blocks.tsand add it tobuilder:import { defineEntryType, f } from "@kwisple/sdk"; import { common } from "./fields"; export const blockQuote = defineEntryType({ handle: "blockQuote", name: "Citaat", icon: "quote", description: "Een uitspraak met naam.", title: false, fields: { quote: f.plainText({ label: "Citaat", multiline: true, required: true }), author: f.plainText({ label: "Naam", charLimit: 80 }), }, }); export const builder = f.matrix({ label: "Inhoud", instructions: "Bouw de pagina op met blokken.", entryTypes: [blockText, blockMedia, blockSplit, blockCards, blockCta, blockFaq, blockQuote], });kwisple devpushes it at once; the block appears in the editor's block picker.Render it. Next: create
src/builder/blocks/quote.tsxand addcase "blockQuote": return <QuoteBlock block={block} />;to the switch insrc/builder/builder.tsx. Astro: createsrc/builder/blocks/Quote.astroand addblockQuote: Quotetocomponentsinsrc/builder/Builder.astro. In both starters a block type without a component is a type error, so you cannot forget one.Use it in the dashboard: add the block to a page, watch the live preview.
Rendering content explains the builder pattern; Blocks and relations the model side.
Step 6: promote the model
npx kwisple push # or: push --dry-run to see the changes firstkwisple push applies cms.config.ts to the live model. Additive changes apply instantly. Destructive changes (a field removed or retyped, a section removed) are blocked with exit code 2 and listed; confirm them with kwisple push --force. Content is never deleted by a push: values stay stored and come back when the field returns. A push that equals the development model clears the pending development model.
What you see in the dashboard: the Contentmodel card shows the new version as uit code (cms.config.ts) and the history of pushes with what changed (red: something was removed; the content stays). kwisple status compares your local model with the platform.
Step 7: connect the repository and deploy
Push your repository to GitHub, then in the dashboard open Website → Instellingen → Ontwikkeling → Hosting & deploys and click Koppel een repository (connect a repository). The sheet asks three things: Host (Waar draait de website?: Cloudflare or Eigen host (deploy hook)), Repository (Repository op GitHub as owner/name, Hoofdbranch, Gebouwd met) and Als inhoud verandert (Alleen verversen for server-rendered sites, Opnieuw bouwen for static sites). Confirm with Koppelen. The whole flow, providers and the platform's own server option are in Hosting and deploys.
Give CI a token so the content model is pushed before every build:
npx kwisple ci-token --gh # creates a read + schema token and stores KWISPLE_URL + KWISPLE_TOKEN as GitHub Actions secretsThe starter's GitHub workflow runs kwisple push --dry-run on pull requests and kwisple push on main. See CI and automation.
Set the production variables at your host (the same names kwisple link wrote to .env, with a production token without the schema scope), set the site's Webhook bij publiceren to https://<site>/api/revalidate and its Preview-URL to https://<site>/api/preview, add the domain under Instellingen → Algemeen → Domein (Domains and DNS) and set the site Online zetten (set online) when it is ready. Until it is live, robots.txt disallows everything and the sitemap is empty.
The start prompt for a coding assistant
If you work with Claude Code or another coding assistant, the dashboard writes the briefing for you. Open Website → Instellingen → Ontwikkeling and under Startprompt voor de ontwikkelaar click Prompt kopiëren (copy) or Downloaden als .md. The prompt holds the steps above, the site's facts (name, slug, languages, address), the client's wish list from Website aanvragen when there is one, the existing content model, the brand kit (voice, colours as --brand-* variables, typography, logo URLs, imagery) and the house rules (model in code, brand through BrandHead, forms and consent through the SDK, no tokens in git). It contains no secrets: kwisple login and kwisple link take care of access.
When something does not work
| Symptom | Fix |
|---|---|
KWISPLE_URL en KWISPLE_TOKEN ontbreken | Run kwisple link in the project folder (or set them in the environment). |
Je sleutel is ingetrokken | The CLI token was revoked under Koppelingen: kwisple login again. |
Je hebt geen klanten waar je een website mag koppelen | Linking needs a seat on the agency's team with the developer right. Ask the agency. |
Deze website is niet op maat gebouwd | Only custom-code sites can be linked. |
| Live preview stays empty | The site's Preview-URL must point at the running dev server's /api/preview; kwisple link fills it in only when empty. |
.env.local zet ook … | .env.local wins over .env; remove the stale keys there. |
Astro: Je site is nog niet gekoppeld page in dev | The integration's middleware shows this when KWISPLE_URL/KWISPLE_TOKEN are missing. Run kwisple link and restart. |
[kwisple] Het contentmodel in je code … is niet wat het platform … gebruikt | Your code and the platform differ: run kwisple dev (development model) or kwisple push. |
More in Troubleshooting and the CLI reference.