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:
curl https://cms.nubisco.io/api/v1/YOUR_SITE/production/about{
"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.blocksis 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
pnpm add @nubisco/cms-vue3. Write a block component
A block component is an ordinary Vue component. It receives the block's fields and knows nothing about the CMS:
<!-- 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
// 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
<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:
# .env
VITE_CMS_API_URL=https://cms.nubisco.io
VITE_CMS_SITE_ID=your-site
VITE_CMS_ENV=productionRun 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:
{
"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
- In the console, open
/aboutand change the title. - Press Save. Your site is unchanged: a save writes a draft.
- Press Submit for review, then Approve.
- Add the document to a release, and publish it.
Reload your site. The new title is there.
What to read next
- Fetching content — routes, partials, caching, error handling
- Rendering blocks — lists, images, links, rich text
- The registry manifest — generating it, and what it prevents
- Preview — showing unpublished content on your site
Not using Vue
Nothing above requires Vue except steps 2–5. The API is plain JSON:
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.