Claude-skills nuxt-content
Nuxt Content v3 Git-based CMS for Markdown/MDC content sites. Use for blogs, docs, content-driven apps with type-safe queries, schema validation (Zod/Valibot), full-text search, navigation utilities. Supports Nuxt Studio production editing, Cloudflare D1/Pages deployment, Vercel deployment, SQL storage, MDC components, content collections.
git clone https://github.com/secondsky/claude-skills
T=$(mktemp -d) && git clone --depth=1 https://github.com/secondsky/claude-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/nuxt-content/skills/nuxt-content" ~/.claude/skills/secondsky-claude-skills-nuxt-content && rm -rf "$T"
plugins/nuxt-content/skills/nuxt-content/SKILL.mdNuxt Content v3
Status: Production Ready Last Updated: 2025-01-10 Dependencies: None Latest Versions: @nuxt/content@^3.0.0, nuxt-studio@^0.1.0-alpha, zod@^4.1.12, valibot@^0.42.0, better-sqlite3@^11.0.0
Overview
Nuxt Content v3 is a powerful Git-based CMS for Nuxt projects that manages content through Markdown, YAML, JSON, and CSV files. It transforms content files into structured data with type-safe queries, automatic validation, and SQL-based storage for optimal performance.
What's New in v3
Major Improvements:
- Content Collections: Structured data organization with type-safe queries, automatic validation, and advanced query builder
- SQL-Based Storage: Production uses SQL (vs. large bundle sizes in v2) for optimized queries and universal compatibility (server/serverless/edge/static)
- Full TypeScript Integration: Automatic types for all collections and APIs
- Enhanced Performance: Ultra-fast data retrieval with adapter-based SQL system
- Nuxt Studio Integration: Self-hosted content editing in production with GitHub sync
When to Use This Skill
Use this skill when:
- Building blogs, documentation sites, or content-heavy applications
- Managing content with Markdown, YAML, JSON, or CSV files
- Implementing Git-based content workflows
- Creating type-safe content queries
- Deploying to Cloudflare (Pages/Workers) or Vercel
- Setting up production content editing with Nuxt Studio
- Building searchable content with full-text search
- Creating navigation systems from content structure
Quick Start (10 Minutes)
1. Install Nuxt Content
# Bun (recommended) bun add @nuxt/content better-sqlite3 # npm npm install @nuxt/content better-sqlite3 # pnpm pnpm add @nuxt/content better-sqlite3
Why this matters:
is the core CMS module@nuxt/content
provides SQL storage for optimal performancebetter-sqlite3- Zero configuration required for basic usage
2. Register Module
// nuxt.config.ts export default defineNuxtConfig({ modules: ['@nuxt/content'] })
CRITICAL:
- Module must be added to
array (notmodules
)buildModules - No additional configuration needed for basic setup
3. Create First Collection
// content.config.ts import { defineContentConfig, defineCollection } from '@nuxt/content' import { z } from 'zod' export default defineContentConfig({ collections: { content: defineCollection({ type: 'page', source: '**/*.md', schema: z.object({ tags: z.array(z.string()).optional(), date: z.date().optional() }) }) } })
Create content file:
<!-- content/index.md --> --- title: Hello World description: My first Nuxt Content page tags: ['nuxt', 'content'] --- # Welcome to Nuxt Content v3 This is my first content-driven site!
4. Query and Render Content
<!-- pages/[...slug].vue --> <script setup> const route = useRoute() const { data: page } = await useAsyncData(route.path, () => queryCollection('content').path(route.path).first() ) </script> <template> <ContentRenderer v-if="page" :value="page" /> </template>
See Full Template:
templates/blog-collection-setup.ts
Critical Rules
Always Do
- Define Collections in
before queryingcontent.config.ts - Use ISO 8601 Date Format:
or2024-01-152024-01-15T10:30:00Z - Restart Dev Server after changing
content.config.ts - Use
to select specific fields (performance).only() - Place MDC Components in
directorycomponents/content/ - Use Zero-Padded Prefixes for numeric sorting:
,01-02- - Install Database Connector:
requiredbetter-sqlite3 - Specify Language in code blocks for syntax highlighting
- Use
in content to separate excerpts<!--more--> - D1 Binding Must Be "DB" (case-sensitive) on Cloudflare
Never Do
- Don't Query Before Defining Collection in
content.config.ts - Don't Use Non-ISO Date Formats (e.g., "January 15, 2024")
- Don't Forget to Restart dev server after config changes
- Don't Query All Fields when you only need some (use
).only() - Don't Place Components outside
components/content/ - Don't Use Single-Digit Prefixes (use
not01-
)1- - Don't Skip Database Connector installation
- Don't Forget Language in code fences
- Don't Expect Excerpts without
divider<!--more--> - Don't Use Different Binding Names for D1 (must be "DB")
Content Collections
Defining Collections
Collections organize related content with shared configuration:
// content.config.ts import { defineCollection, defineContentConfig } from '@nuxt/content' import { z } from 'zod' export default defineContentConfig({ collections: { blog: defineCollection({ type: 'page', source: 'blog/**/*.md', schema: z.object({ title: z.string(), date: z.date(), tags: z.array(z.string()).default([]) }) }), authors: defineCollection({ type: 'data', source: 'authors/*.yml', schema: z.object({ name: z.string(), bio: z.string() }) }) } })
Collection Types
Page Type (type: 'page'
)
type: 'page'Use for: Content that maps to URLs
Features:
- Auto-generates paths from file structure
- Built-in fields:
,path
,title
,description
,bodynavigation - Perfect for: blogs, docs, marketing pages
Path Mapping:
content/index.md → / content/about.md → /about content/blog/hello.md → /blog/hello
Data Type (type: 'data'
)
type: 'data'Use for: Structured data without URLs
Features:
- Complete schema control
- No automatic path generation
- Perfect for: authors, products, configs
Schema Validation
With Zod v4 (Recommended)
bun add -D zod@^4.1.12 # or: npm install -D zod@^4.1.12
import { z } from 'zod' schema: z.object({ title: z.string(), date: z.date(), published: z.boolean().default(false), tags: z.array(z.string()).optional(), category: z.enum(['news', 'tutorial', 'update']) })
With Valibot (Alternative)
bun add -D valibot@^0.42.0 # or: npm install -D valibot@^0.42.0
import * as v from 'valibot' schema: v.object({ title: v.string(), date: v.date(), published: v.boolean(false), tags: v.optional(v.array(v.string())) })
Querying Content
Basic Queries
// Get all posts const posts = await queryCollection('blog').all() // Get single post by path const post = await queryCollection('blog').path('/blog/hello').first() // Get post by ID const post = await queryCollection('blog').where('_id', '=', 'hello').first()
Field Selection
// Select specific fields (performance optimization) const posts = await queryCollection('blog') .only(['title', 'description', 'date', 'path']) .all() // Exclude fields const posts = await queryCollection('blog') .without(['body']) .all()
Where Conditions
// Single condition const posts = await queryCollection('blog') .where('published', '=', true) .all() // Multiple conditions const posts = await queryCollection('blog') .where('published', '=', true) .where('category', '=', 'tutorial') .all() // Operators: =, !=, <, <=, >, >=, in, not-in, like const recent = await queryCollection('blog') .where('date', '>', new Date('2024-01-01')) .all() const tagged = await queryCollection('blog') .where('tags', 'in', ['nuxt', 'vue']) .all()
Ordering and Pagination
// Sort by field const posts = await queryCollection('blog') .sort('date', 'DESC') .all() // Pagination const posts = await queryCollection('blog') .sort('date', 'DESC') .limit(10) .offset(0) .all()
Counting
// Count results const total = await queryCollection('blog') .where('published', '=', true) .count()
Server-Side Queries
// server/api/posts.get.ts export default defineEventHandler(async (event) => { const posts = await queryCollection('blog') .where('published', '=', true) .sort('date', 'DESC') .all() return { posts } })
Navigation
Auto-generate navigation tree from content structure:
const navigation = await queryCollectionNavigation('blog').all()
Returns hierarchical structure:
[ { title: 'Getting Started', path: '/docs/getting-started', children: [{ title: 'Installation', path: '/docs/getting-started/installation' }] } ]
Advanced patterns (filters, ordering, custom structures): See
references/collection-examples.md
MDC Syntax (Markdown Components)
Basic Component Syntax
<!-- Default slot --> ::my-alert This is an alert message :: <!-- Named slots --> ::my-card #title Card Title #default Card content here ::
Component:
<!-- components/content/MyAlert.vue --> <template> <div class="alert"> <slot /> </div> </template>
Props
::my-button{href="/docs" type="primary"} Click me ::
Component:
<!-- components/content/MyButton.vue --> <script setup> defineProps<{ href: string type: 'primary' | 'secondary' }>() </script>
Full-Text Search
// Search across all content const results = await queryCollectionSearchSections('blog', 'nuxt content') .where('published', '=', true) .all()
Returns:
[ { id: 'hello', path: '/blog/hello', title: 'Hello World', content: '...matching text...' } ]
Deployment
Cloudflare Pages + D1
bun add -D @nuxthub/core bunx wrangler d1 create nuxt-content bun run build && bunx wrangler pages deploy dist
wrangler.toml:
[[d1_databases]] binding = "DB" # Must be exactly "DB" (case-sensitive) database_name = "nuxt-content" database_id = "your-database-id"
CRITICAL: D1 binding MUST be named
DB (case-sensitive).
See:
references/deployment-checklists.md for complete Cloudflare deployment guide with troubleshooting.
Vercel
// nuxt.config.ts export default defineNuxtConfig({ modules: ['@nuxt/content'], routeRules: { '/blog/**': { prerender: true } } })
vercel deploy
See:
references/deployment-checklists.md for complete Vercel configuration and prerender strategy.
Nuxt Studio Integration
Enable Studio
bun add -D nuxt-studio@alpha # or: npm install -D nuxt-studio@alpha
// nuxt.config.ts export default defineNuxtConfig({ modules: ['@nuxt/content', 'nuxt-studio'], studio: { enabled: true, gitInfo: { name: 'your-name', email: 'your-email@example.com' } } })
OAuth Setup
- Create GitHub OAuth App
- Set Authorization callback URL:
https://yourdomain.com/api/__studio/oauth/callback - Add client ID and secret to environment variables
CRITICAL: Callback URL must match production domain exactly (including
https://).
Top 5 Critical Issues
Issue #1: Collection Not Found
Error:
Collection 'xyz' not found
Solution: Define collection in
content.config.ts and restart dev server
rm -rf .nuxt && bun dev
Issue #2: Date Validation Failure
Error:
Validation error: Expected date, received string
Solution: Use ISO 8601 format:
--- date: 2024-01-15 # ✅ Correct # NOT: "January 15, 2024" # ❌ Wrong ---
Issue #3: D1 Binding Not Found (Cloudflare)
Error:
DB is not defined
Solution: D1 binding name must be exactly
DB (case-sensitive) in Cloudflare dashboard.
Issue #4: MDC Components Not Rendering
Error: Components show as raw text
Solution: Place components in
components/content/ with exact name matching:
<!-- components/content/MyAlert.vue -->
::my-alert Content ::
Issue #5: Navigation Not Updating
Error: New content doesn't appear in navigation
Solution: Clear
.nuxt cache:
rm -rf .nuxt && bun dev
See All 18 Issues:
references/error-catalog.md
When to Load References
Load
when:references/error-catalog.md
- User encounters error beyond Top 5 shown above
- Debugging collection validation, schema errors, or deployment issues
- Need complete error catalog with all 18 documented solutions and sources
Load
when:references/collection-examples.md
- Setting up advanced collection types (data vs page)
- Implementing complex schema validation patterns
- Need examples for Zod v4 or Valibot schemas
- Working with multiple collection configurations
Load
when:references/query-operators.md
- Building complex queries beyond basic examples
- Need full reference of all operators (=, !=, <, >, <=, >=, in, not-in, like)
- Implementing pagination, sorting, or field selection
- Troubleshooting query syntax errors
Load
when:references/deployment-checklists.md
- Deploying to specific platform (Cloudflare Pages, Cloudflare Workers D1, Vercel)
- Setting up production environment configurations
- Troubleshooting deployment-specific errors (D1 binding, prerender routes)
- Need platform-specific wrangler.toml or vercel.json examples
Load
when:references/mdc-syntax-reference.md
- Implementing custom MDC (Markdown Components)
- Debugging component rendering issues
- Need complete syntax reference for props, slots, nesting
- Creating advanced content components
Load
when:references/studio-setup-guide.md
- Setting up Nuxt Studio for production content editing
- Configuring GitHub OAuth authentication
- Enabling self-hosted content editing with GitHub sync
- Troubleshooting Studio authentication or Git sync issues
Templates (
templates/):
- Complete blog setup with collections, queries, navigation, search, and deployment (334 lines)blog-collection-setup.ts
Performance Tips
- Use
to select specific fields.only() - Enable Caching for production
- Use Pagination for large collections
- Prerender Static Routes on Vercel
- Use SQL Storage (better-sqlite3) for optimal performance
Best Practices
- Always define collections before querying
- Use TypeScript for type-safe queries
- Validate schemas with Zod or Valibot
- Place MDC components in
components/content/ - Use ISO 8601 date format
- Add
for excerpts<!--more--> - Specify language in code blocks
- Clear
after config changes.nuxt - For Cloudflare: D1 binding must be "DB"
- Use pagination for large datasets
Integration with Other Skills
This skill composes well with:
- nuxt-v4 → Core Nuxt framework
- nuxt-ui-v4 → UI component library
- cloudflare-worker-base → Cloudflare deployment
- tailwind-v4-shadcn → Styling
- drizzle-orm-d1 → Additional database queries
- cloudflare-d1 → Database integration
Additional Resources
Official Documentation:
- Nuxt Content Docs: https://content.nuxt.com
- GitHub: https://github.com/nuxt/content
- Nuxt Studio: https://nuxt.studio
Examples:
- Official Examples: https://github.com/nuxt/content/tree/main/examples
- Starter Templates: https://github.com/nuxt-themes
Production Tested: Documentation sites, blogs, content platforms Last Updated: 2025-01-27 Token Savings: ~60% (reduces content + error documentation)