Kwisple
Browse the docs

Content model

Site kits: seed and export

Starting content as one JSON file, written into a site with kwisple seed and made from a finished site with kwisple export.

A site kit is a site's starting content as one JSON file without ids: entries with their field values and the values of the global sets. It is how a new site gets real pages to design against, and how you reuse the content of a site you built as a starting point for the next one. Two CLI commands work with kits:

CommandWhat it does
kwisple seed [bestand] [--force]Writes a kit into the linked site, published, through the same engine as the editor. Default file: cms/seed.json.
kwisple export [bestand]Saves the linked site's live content as a kit. Default file: cms/seed.json.

Both need a token with the schema scope (Contentmodel pushen), the one kwisple link writes to .env, and both only work for custom-code sites.

The file: cms/seed.json

{
  "version": 1,
  "locale": "nl",
  "entries": [
    {
      "section": "home",
      "title": "Home",
      "fields": {
        "heroHeading": "Vakwerk waar je op kunt rekenen",
        "heroIntro": "Wij helpen bedrijven en gezinnen in de regio.",
        "builder": [
          {
            "type": "blockText",
            "fields": { "heading": "Wat we doen", "text": "<p>Een korte uitleg van je diensten.</p>" }
          }
        ]
      }
    },
    { "key": "diensten", "section": "pages", "title": "Diensten", "slug": "diensten" },
    {
      "section": "pages",
      "parent": "diensten",
      "title": "Advies",
      "slug": "advies",
      "fields": { "intro": "Een eerste gesprek, vrijblijvend." }
    },
    {
      "section": "news",
      "title": "We zijn online",
      "seo": { "description": "Onze nieuwe website staat online." }
    }
  ],
  "globals": {
    "contact": { "phone": "+32 000 00 00 00", "email": "info@example.com" }
  }
}

Top level

KeyTypeRequiredMeaning
version1yesThe kit format. Only 1 exists.
localestringnoThe language the texts are written in. export fills in the site's default language. On seed, texts always go into the target site's default language.
entriesarrayyesAt most 500 entries, in order.
globalsobjectnoGlobal set handle → field values.

An entry

KeyTypeRequiredMeaning
sectionstringyesSection handle. Must exist in the site's content model.
typestringnoEntry type handle. Default: the first entry type of the section.
keystringnoAny string unique in the file, so later entries can name this one as parent.
parentstringnoStructures only: the key of the parent entry, which must come earlier in the file.
titlestringnoThe title.
slugstringnoThe slug; without one the entry keeps the slug it got when it was created.
fieldsobjectnoField values by handle, in their stored shape (see below).
seoobjectnoThe entry's SEO values.

Handles and strings are capped: section, type, key and parent at 64 characters, title and slug at 200.

Field values

Values use the stored shape of each field kind, the same shape the editor saves (see Fields reference). Two things differ from content you read through the API:

  • Matrix blocks are written as { "type": "<entry type>", "fields": { … } }, optionally with title and enabled. The seed gives every block a fresh id.
  • Relations are ids. Assets, entry relations and links to entries or assets point at ids that only exist in one site. export leaves them out; in a hand-written kit, leave them out too.

Rich text is HTML and is sanitised on publish like everything an editor writes.

Singles and structures

  • A single section has exactly one entry. A kit entry for a single fills the existing entry (the platform creates it when the model is pushed) instead of making a second one.
  • In a structure, give the parent a key and the child "parent": "<key>". The parent must come earlier in the file; export orders entries by level for that reason. The section's maxLevels applies.

kwisple seed

npx kwisple push               # the content model first
npx kwisple seed               # cms/seed.json
npx kwisple seed kits/horeca.json
npx kwisple seed --force       # also into a site that already has content
  1. The CLI reads the file (missing: seed.json niet gevonden. Maak er een met kwisple export.) and posts it to POST /api/v1/seed.
  2. The platform refuses a site that already has content of its own with 409 Deze site heeft al inhoud. Gebruik --force om de kit er toch bij te zetten. Singles that are still empty do not count as content.
  3. Per entry it creates the entry, applies the kit's values to the default language and publishes it through the normal publishing engine: validation (required fields, limits, allowed block types), unique slugs and URIs, sanitising, a revision with the note Site kit.
  4. Per global set it saves the values the same way.
  5. It purges the platform's cached answers for the site.

The CLI then prints ✔ <n> pagina's en <n> globals gezet uit seed.json. followed by one line per problem. A line that cannot be placed does not stop the rest:

ProblemWhy
<section> (#<n>): sectie bestaat niet in het contentmodel.the section handle is not in the pushed model; push first
<section> “<title>” (#<n>): <reason>the entry did not publish, e.g. a required field is empty or a value has the wrong shape
Global <handle>: bestaat niet in het contentmodel.the global set is not in the model
Global <handle>: <reason>a global value did not validate

When there are problems and not a single entry was published, the platform answers 422 instead of 200. The CLI lists the problems all the same and exits with code 1, so CI notices; usually the model was not pushed yet or the section handles in the kit do not match it.

--force

--force skips the "already has content" check. It adds the kit's entries next to the existing ones; nothing is replaced or deleted. Singles are the exception: their existing entry is filled with the kit's values and published. Use it on a site you are still setting up, never on a client's live site.

kwisple export

npx kwisple export                    # writes cms/seed.json
npx kwisple export kits/my-client.json

GET /api/v1/seed returns the site's live content in the default language as a kit:

  • every entry that is not in the trash and is enabled in the default language, ordered by structure level and position;
  • key is the entry's id and parent its parent's id, so structures survive the trip;
  • title, slug, fields (shared and translated values merged), and seo when set;
  • the values of every global set that has any;
  • disabled matrix blocks are dropped; the remaining blocks lose their ids.

What a kit never carries: uploaded files (f.assets fields), relations to other entries (f.entries fields) and links of type entry or asset. A kit travels between sites, and those ids would point nowhere. The CLI says so after writing the file: Afbeeldingen, bestanden en links naar andere pagina's gaan niet mee in een kit.

Export reads the live model of the site. Entries whose entry type is no longer in the model are skipped.

The starters' kits

npm create kwisple-site can start a project with content. The interactive question Met welke inhoud starten? offers:

ChoiceKitContents
Leegnoneonly the content model
Dienstverlenerdienstverlenerhome, Over ons, Diensten with two child pages, Contact, one news article; globals contact and footer
Horecahorecahome, Menu, Reserveren, Over ons, one news article; globals contact and footer

Non-interactively:

npm create kwisple-site@latest acme-site -- --kit dienstverlener
npm create kwisple-site@latest acme-site -- --kit horeca
npm create kwisple-site@latest acme-site -- --kit geen      # no kit

The chosen kit is copied to cms/seed.json, and the printed next steps include kwisple push (the content model) and kwisple seed (the starting content) before kwisple dev. The kit files live in packages/create-kwisple-site/kits/ in the platform repository.

The kits are written for the starters' content model: sections home, pages and news, the page-builder field builder with blockText blocks, and the global sets contact and footer. If you change those handles in your project, change cms/seed.json along with them.

The kit test

packages/sdk/test/kits.test.ts checks every kit in packages/create-kwisple-site/kits/ against the content model of both starters (starters/astro/cms.config.ts and starters/next/cms.config.ts). For every entry it checks that:

  • the section exists;
  • a parent names a key that came earlier in the file;
  • the entry type exists (the given type, or the section's first);
  • the field values pass the strict stored-value validation of that entry type, with required fields filled and matrix blocks of allowed types.

Global values are checked against their global set the same way. Run it with the SDK's tests:

pnpm --filter @kwisple/sdk test

When you change a starter's cms.config.ts (rename a block, add a required field), this test tells you which kit needs updating. A new kit is picked up automatically: drop a .json file in the kits folder and add it to kits in packages/create-kwisple-site/src/template.ts so the create command offers it.

Typical flows

A new client site from a starter

npm create kwisple-site@latest bakkerij-site -- --kit horeca
cd bakkerij-site
npx kwisple login
npx kwisple link
npx kwisple push
npx kwisple seed
npx kwisple dev

Reusing a finished site as a template

  1. In the finished site's project: npx kwisple export kits/template.json.
  2. Copy cms.config.ts, cms/ and the kit to the new project.
  3. In the new project: npx kwisple link, npx kwisple push, npx kwisple seed kits/template.json.
  4. Add images and links between pages in the dashboard; the kit left them out.

Where to go next

Last updated 2026-10-30