Nuxt Integration Guide
This guide provides resources and information for integrating Sveltia CMS with Nuxt, a popular Vue.js framework for building server-side rendered and static websites.
Examples
See real-world examples of Nuxt integrations in our Showcase. Most of the listed sites include links to their source code, so you can explore how they implemented Sveltia CMS with Nuxt.
Setup
Adding the Admin Page
Nuxt serves static files from the public folder. Create public/admin/index.html and public/admin/config.yml as described in the Getting Started guide. The admin page is then available at /admin/ on both the development server and the production site.
If your project still uses Nuxt 2, the static files folder is static instead of public.
Linking to the Admin Page
The admin page is not part of your Nuxt app. If you link to it with the <NuxtLink> component, add the external prop so that Vue Router doesn’t try to render it as a page:
<NuxtLink to="/admin/" external>Edit content</NuxtLink>A regular <a href="/admin/"> element works as well.
Configuration
Most Nuxt sites manage Markdown content with the Nuxt Content module, which reads files from the content folder. In Nuxt Content v3, the files are grouped into collections defined in content.config.ts, and each collection’s front matter can be validated with a Zod schema:
import { defineCollection, defineContentConfig } from '@nuxt/content';
import { z } from 'zod';
export default defineContentConfig({
collections: {
blog: defineCollection({
type: 'page',
source: 'blog/*.md',
schema: z.object({
date: z.date(),
image: z.string().optional(),
tags: z.array(z.string()).optional(),
}),
}),
},
});The matching Sveltia CMS entry collection uses the folder of the source pattern, prefixed with content/. title and description are built-in fields of a page collection, so they don’t need to be defined in the schema, but they should be added to the CMS configuration:
media_folder: public/images
public_folder: /images
output:
omit_empty_optional_fields: true
collections:
- name: blog
label: Blog
folder: content/blog
create: true
fields:
- { name: title, label: Title }
- { name: description, label: Description, required: false }
- { name: date, label: Date, widget: datetime }
- { name: image, label: Cover Image, widget: image, required: false }
- { name: tags, label: Tags, widget: list, required: false }
- { name: body, label: Body, widget: markdown }The omit_empty_optional_fields output option keeps empty optional fields out of the front matter. Without it, empty fields are saved as an empty string, an empty array or null depending on the field type, which may not pass your schema. For example, z.string().optional() accepts a missing property but rejects null.
Loading Content
Query a collection with queryCollection and render the Markdown body with the <ContentRenderer> component. For example, a catch-all page like app/pages/[...slug].vue can find the entry whose path matches the current route.
Nuxt Content parses the content files when the site is built, so the site must be rebuilt to reflect content changes made in the CMS. Most hosting services rebuild the site automatically when a commit is pushed to the repository.