TL;DR: This guide walks through setting up both Nuxt Content and Sanity from scratch. You'll see the exact commands, configuration files, and code needed to get a blog running with each CMS. By the end, you'll understand the setup complexity and developer experience of each approach.
What We're Building
A simple blog with:
- A list of posts on the homepage
- Individual post pages with full content
- Author information on each post
- TypeScript support throughout
Part 1: Setting Up Nuxt Content
Step 1: Create the Project
npx nuxi init my-blogcd my-blognpm installnpm install @nuxt/contentStep 2: Configure Nuxt
1export default defineNuxtConfig({2 modules: ['@nuxt/content'],3 content: {4 highlight: {5 theme: 'github-dark'6 }7 }8})Step 3: Create Your First Post
Create a content directory and add your first markdown file:
1---2title: Hello World3description: My first blog post4author: John Doe5publishedAt: 2025-01-156tags:7 - getting-started8 - nuxt9---10
11# Hello World12
13This is my first blog post using Nuxt Content!14
15## Why Nuxt Content?16
17Nuxt Content makes it easy to create content-driven websites.Step 4: Create the Blog List Page
1<template>2 <div>3 <h1>Blog</h1>4 <ul>5 <li v-for="post in posts" :key="post._path">6 <NuxtLink :to="post._path">7 {{ post.title }}8 </NuxtLink>9 <p>{{ post.description }}</p>10 </li>11 </ul>12 </div>13</template>14
15<script setup lang="ts">16const { data: posts } = await useAsyncData('blog-posts', () =>17 queryContent('blog')18 .only(['title', 'description', '_path', 'publishedAt'])19 .sort({ publishedAt: -1 })20 .find()21)22</script>Step 5: Create the Post Detail Page
1<template>2 <article>3 <ContentDoc v-slot="{ doc }">4 <h1>{{ doc.title }}</h1>5 <p>By {{ doc.author }} • {{ formatDate(doc.publishedAt) }}</p>6 <ContentRenderer :value="doc" />7 </ContentDoc>8 </article>9</template>10
11<script setup lang="ts">12const formatDate = (date: string) => {13 return new Date(date).toLocaleDateString('en-US', {14 year: 'numeric',15 month: 'long',16 day: 'numeric'17 })18}19</script>That's It!
Part 2: Setting Up Sanity
Step 1: Create the Nuxt Project
npx nuxi init my-sanity-blogcd my-sanity-blognpm installnpm install @sanity/client @sanity/image-urlStep 2: Create a Sanity Project
npm create sanity@latest -- --template blog --create-project "My Blog" --dataset productionThis creates a Sanity Studio with pre-configured blog schemas. You'll get a project ID that you'll need for the next step.
Step 3: Configure the Sanity Client
1import { createClient } from '@sanity/client'2import imageUrlBuilder from '@sanity/image-url'3
4export const client = createClient({5 projectId: 'your-project-id',6 dataset: 'production',7 useCdn: true,8 apiVersion: '2024-01-01'9})10
11const builder = imageUrlBuilder(client)12export const urlFor = (source: any) => builder.image(source)Step 4: Define Your Schema (in Sanity Studio)
1export default {2 name: 'post',3 title: 'Post',4 type: 'document',5 fields: [6 {7 name: 'title',8 title: 'Title',9 type: 'string',10 validation: (Rule: any) => Rule.required()11 },12 {13 name: 'slug',14 title: 'Slug',15 type: 'slug',16 options: { source: 'title' }17 },18 {19 name: 'author',20 title: 'Author',21 type: 'reference',22 to: [{ type: 'author' }]23 },24 {25 name: 'publishedAt',26 title: 'Published At',27 type: 'datetime'28 },29 {30 name: 'body',31 title: 'Body',32 type: 'array',33 of: [{ type: 'block' }]34 }35 ]36}Step 5: Create the Blog List Page
1<template>2 <div>3 <h1>Blog</h1>4 <ul>5 <li v-for="post in posts" :key="post._id">6 <NuxtLink :to="`/blog/${post.slug.current}`">7 {{ post.title }}8 </NuxtLink>9 </li>10 </ul>11 </div>12</template>13
14<script setup lang="ts">15import { client } from '~/lib/sanity'16
17const { data: posts } = await useAsyncData('posts', () =>18 client.fetch(`19 *[_type == "post"] | order(publishedAt desc) {20 _id,21 title,22 slug,23 publishedAt,24 "author": author->name25 }26 `)27)28</script>Step 6: Create the Post Detail Page
1<template>2 <article v-if="post">3 <h1>{{ post.title }}</h1>4 <p>By {{ post.author }} • {{ formatDate(post.publishedAt) }}</p>5 <SanityContent :blocks="post.body" />6 </article>7</template>8
9<script setup lang="ts">10import { client } from '~/lib/sanity'11
12const route = useRoute()13const { data: post } = await useAsyncData(`post-${route.params.slug}`, () =>14 client.fetch(`15 *[_type == "post" && slug.current == $slug][0] {16 title,17 body,18 publishedAt,19 "author": author->name20 }21 `, { slug: route.params.slug })22)23
24const formatDate = (date: string) => {25 return new Date(date).toLocaleDateString('en-US', {26 year: 'numeric',27 month: 'long',28 day: 'numeric'29 })30}31</script>Additional Setup Required
Setup Comparison Summary
Here's how the two approaches compare:
- Dependencies: Nuxt Content needs 1 package; Sanity needs 2+ packages plus a separate studio project
- Configuration: Nuxt Content is 5 lines; Sanity requires client setup, schema definitions, and studio config
- Content Creation: Nuxt Content uses markdown files; Sanity uses a visual Studio interface
- Query Syntax: Nuxt Content uses queryContent(); Sanity uses GROQ queries
- Time to First Post: Nuxt Content takes ~5 minutes; Sanity takes ~20 minutes
Quick Decision Tree
Which Should You Choose?
- Will non-developers edit content regularly? Yes → Sanity. No → Continue.
- Do you need real-time collaboration? Yes → Sanity. No → Continue.
- Is your budget $0? Yes → Nuxt Content. No → Continue.
- Do you want git-based version control for content? Yes → Nuxt Content. No → Sanity.
- Building a personal blog or docs site? Yes → Nuxt Content.
- Building for a client or team? Consider Sanity.
Next Steps
Now that you've seen both setups, here's what to explore next:
For Nuxt Content:
- Learn MDC syntax for embedding Vue components in markdown
- Set up content collections with Zod schemas (v3)
- Explore Nuxt Studio for visual editing
For Sanity:
- Master GROQ queries for complex data fetching
- Set up preview mode for draft content
- Configure image optimization with the Sanity image pipeline
Both options will serve you well—the right choice depends on your specific project needs and team composition. Happy building!
// nuxt.config.tsexport default defineNuxtConfig({ modules: ['@nuxt/content'], content: { highlight: { theme: 'github-dark' }, markdown: { toc: { depth: 3 } } }})// sanity.config.tsimport { defineConfig } from 'sanity'import { structureTool } from 'sanity/structure'
export default defineConfig({ projectId: 'your-project-id', dataset: 'production', plugins: [structureTool()], schema: { types: schemaTypes }})| Requirement | Nuxt Content | Sanity |
|---|---|---|
| Account Required | No | Yes (free tier available) |
| Time to First Content | ~5 minutes | ~15 minutes |
| Dependencies | 1 package | 2-3 packages |
| Configuration Files | nuxt.config.ts only | sanity.config.ts + schema files |
| Content Location | Local /content folder | Cloud Content Lake |
Nuxt Content Installation Guide
Step-by-step installation guide for setting up Nuxt Content in your project.
content.nuxt.com
Sanity Getting Started
Official getting started guide for Sanity - from zero to published content.
sanity.io