Skip to content

Build your first site

By the end of this you will have a page whose content comes from the CMS, and which someone can edit in a browser without touching your code.

You need Node 20+ and a CMS project. This uses Vue; the last section covers everything else.

1. Fetch a document

Content is public JSON over HTTP. There is no SDK to install and no key to configure:

bash
curl https://cms.nubisco.io/api/v1/YOUR_SITE/production/about
json
{
  "route": "/about",
  "meta": { "title": "About us", "description": "Who we are." },
  "zones": {
    "main": {
      "blocks": [
        {
          "id": "hero",
          "type": "brand-hero",
          "fields": { "title": "We build software", "subtitle": "Since 2019." }
        }
      ]
    }
  }
}

Three things to notice, because the rest of the tutorial is built on them:

  • zones.main.blocks is an ordered list of sections.
  • Each block has a type, which names one of your components.
  • Each block has fields, which are that component's props.

2. Install the Vue package

bash
pnpm add @nubisco/cms-vue

3. Write a block component

A block component is an ordinary Vue component. It receives the block's fields and knows nothing about the CMS:

vue
<!-- src/blocks/BrandHero.vue -->
<script setup lang="ts">
defineProps<{
  fields: {
    title?: string
    subtitle?: string
  }
}>()
</script>

<template>
  <section class="hero">
    <h1>{{ fields.title }}</h1>
    <p>{{ fields.subtitle }}</p>
  </section>
</template>

4. Map types to components

ts
// src/cms/registry.ts
import BrandHero from '@/blocks/BrandHero.vue'

export const registry = {
  'brand-hero': BrandHero,
}

The key is the block type's API id, exactly as it appears in type.

5. Render the document

vue
<script setup lang="ts">
import { CmsDocument } from '@nubisco/cms-vue'
import { registry } from '@/cms/registry'
</script>

<template>
  <CmsDocument route="/about" :registry="registry" />
</template>

Configure where content comes from:

bash
# .env
VITE_CMS_API_URL=https://cms.nubisco.io
VITE_CMS_SITE_ID=your-site
VITE_CMS_ENV=production

Run your dev server. The page renders from the CMS, and editing that content in the console changes what you see on reload.

Your machine can read production

CORS is open, so a local dev server reads live content directly. You do not need a local CMS, a database, or a seed file.

6. Publish a registry manifest

Before content can be published, the CMS needs to know which block types your site can actually render. Serve a file at /cms-registry.json:

json
{
  "revision": "a1b2c3",
  "site": "your-site",
  "blockTypes": ["brand-hero"],
  "cutoverRoutes": []
}

Generate it from your registry so the two cannot disagree — see The registry manifest.

Then in the console, open Releases and press the refresh control next to the registry badge to read it.

7. Publish a change

  1. In the console, open /about and change the title.
  2. Press Save. Your site is unchanged: a save writes a draft.
  3. Press Submit for review, then Approve.
  4. Add the document to a release, and publish it.

Reload your site. The new title is there.

Not using Vue

Nothing above requires Vue except steps 2–5. The API is plain JSON:

js
const doc = await fetch(
  `${API}/api/v1/${SITE}/${ENV}/${route}`,
).then((r) => r.json())

for (const block of doc.zones.main.blocks) {
  render(componentFor(block.type), block.fields)
}

@nubisco/cms-core is framework-agnostic and gives you the types and link helpers without any Vue.

A Nubisco product. Not open source.