
Nuxt Seo
- 2.3k installs
- 696 repo stars
- Updated July 27, 2026
- onmax/nuxt-skills
nuxt-seo configures the @nuxtjs/seo module stack for Nuxt site config, crawlability, OG images, and JSON-LD.
About
The nuxt-seo skill guides configuration of the @nuxtjs/seo meta-module stack for Nuxt applications. Install via npx nuxi module add @nuxtjs/seo, then load only the reference files relevant to the current task rather than all at once for token efficiency. It covers site URL and name foundation via nuxt-site-config and useSiteConfig, robots.txt with useRobotsRule, sitemap generation with defineSitemapEventHandler, dynamic OG images via defineOgImage, JSON-LD through nuxt-schema-org, and utilities like breadcrumbs and canonical URLs. Nuxt Content v3 integrates via asSeoCollection for automatic sitemap, og-image, and schema-org from frontmatter when @nuxtjs/seo loads before @nuxt/content. The module overview table maps each package to purpose and key APIs. Main skill stays around 250 tokens with sub-files at 400 to 600 tokens each. Token-efficient loading keeps the main skill near 250 tokens. See SKILL.md for the authoritative workflow and constraints.
- Install @nuxtjs/seo and load only task-relevant reference files.
- Site config via useSiteConfig underpins robots, sitemap, OG, and schema.
- asSeoCollection wires Content v3 frontmatter to SEO modules.
- Module table maps robots, sitemap, og-image, schema-org, and link checker.
- Load @nuxtjs/seo before @nuxt/content in the modules array.
Nuxt Seo by the numbers
- 2,308 all-time installs (skills.sh)
- +39 installs in the week ending Aug 5, 2026 (Skillselion tracking)
- Ranked #258 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 5, 2026 (Skillselion catalog sync)
nuxt-seo capabilities & compatibility
- Capabilities
- site config foundation with usesiteconfig · robots and sitemap module setup · dynamic og image and json ld configuration · nuxt content v3 asseocollection integration · progressive reference file loading for token eff
- Use cases
- seo · frontend
What nuxt-seo says it does
DO NOT load all files at once.
Foundation for all SEO modules.
npx skills add https://github.com/onmax/nuxt-skills --skill nuxt-seoAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 2.3k |
|---|---|
| repo stars | ★ 696 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 27, 2026 |
| Repository | onmax/nuxt-skills ↗ |
How do I set up SEO, sitemaps, OG images, and structured data in a Nuxt app?
Configure Nuxt SEO modules for site config, robots, sitemaps, OG images, and JSON-LD structured data.
Who is it for?
Nuxt apps needing @nuxtjs/seo configuration or Nuxt Content SEO frontmatter.
Skip if: Skip for non-Nuxt frameworks or generic marketing copy; use nuxt-content skill for MDC rendering.
When should I use this skill?
User mentions Nuxt SEO, sitemap, robots, og-image, schema-org, or asSeoCollection.
What you get
Correct module setup and APIs for site config, robots, sitemap, og-image, and schema-org.
- robots.txt
- sitemap.xml
- per-page robots rules
Files
Nuxt SEO
npx nuxi module add @nuxtjs/seoWhen to Use
Working with:
- SEO configuration (site URL, name, indexability)
- Robots.txt and sitemap.xml generation
- Dynamic OG image generation
- JSON-LD structured data (schema.org)
- Breadcrumbs and canonical URLs
Loading Files
Consider loading these reference files based on your task:
- [ ] references/site-config.md - if configuring site URL, name, or SEO foundation
- [ ] references/crawlability.md - if setting up robots.txt or sitemap.xml
- [ ] references/og-image.md - if generating dynamic OG images
- [ ] references/schema-org.md - if adding JSON-LD structured data
- [ ] references/utilities.md - if working with breadcrumbs, canonical URLs, or link checking
DO NOT load all files at once. Load only what's relevant to your current task.
Site Config
Foundation for all SEO modules. Configure site in nuxt.config.ts, access via useSiteConfig(). See references/site-config.md for full options.
Module Overview
| Module | Purpose | Key API |
|---|---|---|
| nuxt-site-config | Shared config | useSiteConfig() |
| @nuxtjs/robots | robots.txt | useRobotsRule() |
| @nuxtjs/sitemap | sitemap.xml | defineSitemapEventHandler() |
| nuxt-og-image | OG images | defineOgImage() |
| nuxt-schema-org | JSON-LD | useSchemaOrg() |
| nuxt-seo-utils | Meta utilities | useBreadcrumbItems() |
| nuxt-link-checker | Link validation | Build-time checks |
Nuxt Content v3
Use asSeoCollection() for automatic sitemap, og-image, and schema-org from frontmatter:
// content.config.ts
import { defineCollection, defineContentConfig } from '@nuxt/content'
import { asSeoCollection } from '@nuxtjs/seo/content'
export default defineContentConfig({
collections: {
posts: defineCollection(asSeoCollection({ type: 'page', source: 'posts/**' }))
}
})Important: Load @nuxtjs/seo before @nuxt/content in modules array:
export default defineNuxtConfig({
modules: ['@nuxtjs/seo', '@nuxt/content']
})Frontmatter fields: ogImage, sitemap, robots, schemaOrg.
Related Skills
- nuxt-content - For MDC rendering with SEO frontmatter
Links
Token Efficiency
Main skill: ~250 tokens. Each sub-file: ~400-600 tokens. Only load files relevant to current task.
Crawlability: Robots & Sitemap
Robots.txt
Auto-generated at /robots.txt. Respects site.indexable setting.
Configuration
// nuxt.config.ts
export default defineNuxtConfig({
robots: {
// Block AI crawlers
blockAiBots: true,
// Block non-SEO bots (reduces server load)
blockNonSeoBots: true,
// Custom rules
groups: [
{ userAgent: '*', disallow: ['/admin'] }
]
}
})Per-Page Control
// Disable indexing
useRobotsRule('noindex, nofollow')
// Object syntax with AI directives
useRobotsRule({
noindex: true,
nofollow: true,
noai: true, // Block AI training
noimageai: true, // Block AI image training
'max-snippet': 150, // Preview controls
'max-image-preview': 'large'
})Route rules:
export default defineNuxtConfig({
routeRules: {
'/admin/**': { robots: 'noindex, nofollow' },
'/hidden': { robots: false }
}
})Nuxt Content Frontmatter
---
robots: noindex, nofollow
# Or structured:
robots:
noindex: true
nofollow: true
---Sitemap.xml
Auto-generated at /sitemap.xml from app routes.
Configuration
// nuxt.config.ts
export default defineNuxtConfig({
sitemap: {
sources: ['/api/__sitemap__/urls'],
exclude: ['/admin/**', '/secret'],
// For static sites - no runtime generation
zeroRuntime: true
}
})Dynamic URLs via API
// server/api/__sitemap__/urls.ts
import { defineSitemapEventHandler } from '#imports'
import type { SitemapUrlInput } from '#sitemap/types'
export default defineSitemapEventHandler(async () => {
const posts = await $fetch('/api/posts')
return posts.map(post => ({
loc: post.path,
lastmod: post.updatedAt,
// Image sitemap
images: [{ loc: post.image, title: post.title }],
// Video sitemap
videos: [{ content_loc: post.videoUrl, title: post.title }]
} satisfies SitemapUrlInput))
})Per-Page Control
Route rules:
export default defineNuxtConfig({
routeRules: {
'/blog/**': { sitemap: { changefreq: 'daily', priority: 0.9 } },
'/hidden': { sitemap: false }
}
})Nuxt Content frontmatter:
---
sitemap:
changefreq: weekly
priority: 0.8
lastmod: 2025-01-15
---Multiple Sitemaps
For large sites:
export default defineNuxtConfig({
sitemap: {
sitemaps: {
pages: { include: ['/**'], exclude: ['/blog/**'] },
blog: { include: ['/blog/**'] }
}
}
})Generates /pages-sitemap.xml, /blog-sitemap.xml, and /sitemap_index.xml.
i18n Sitemaps
With @nuxtjs/i18n, auto-generates per-locale sitemaps with hreflang alternates.
Debug
In development:
- Robots: Check
/robots.txtdirectly - Sitemap: Visit
/__sitemap__/debug.jsonfor raw data
OG Image Generation
Dynamic Open Graph image generation using Vue components.
Quick Start
// Component-first (recommended)
defineOgImage('NuxtSeo', { title: 'My Page Title' })
// Object syntax
defineOgImage({ component: 'NuxtSeo', title: 'My Page Title' })
// Disable OG image
defineOgImage(false)Built-in Template
The NuxtSeo template supports:
defineOgImage('NuxtSeo', {
title: 'Hello World',
description: 'My description',
theme: '#3b82f6',
colorMode: 'dark',
icon: 'carbon:cloud',
siteName: 'My Site',
siteLogo: '/logo.png'
})Multiple Images Per Page
Use key for platform-specific images:
// Default OG image (1200x600)
defineOgImage('NuxtSeo', { title: 'Default' })
// Square for WhatsApp (800x800)
defineOgImage('NuxtSeo', {
title: 'Square',
key: 'square',
width: 800,
height: 800
})Custom Vue Components
Create in components/OgImage/:
<!-- components/OgImage/Blog.vue -->
<script setup lang="ts">
defineProps<{ title: string; author: string }>()
</script>
<template>
<div class="w-full h-full flex flex-col justify-center items-center bg-gradient-to-br from-blue-500 to-purple-600 p-12">
<h1 class="text-6xl font-bold text-white text-center">{{ title }}</h1>
<p class="text-2xl text-white/80 mt-4">By {{ author }}</p>
</div>
</template>Use in pages:
defineOgImage('OgImageBlog', { title: 'My Post', author: 'John' })Renderers
| Renderer | Speed | CSS Support | Edge | Best For |
|---|---|---|---|---|
| satori | Fast | Partial | ✅ | Default, most templates |
| chromium | Slow | Full | ❌ | Complex designs, prerender |
export default defineNuxtConfig({
ogImage: {
defaults: { renderer: 'satori' }
}
})Satori Limitations
- No
display: grid- useflex - No
position: absolutewithout explicit dimensions - Fonts: use
@nuxt/fontswithglobal: truefor best results
Configuration
export default defineNuxtConfig({
ogImage: {
defaults: {
component: 'NuxtSeo',
width: 1200,
height: 600,
cacheMaxAgeSeconds: 60 * 60 * 24 * 3 // 3 days
},
// For static sites
zeroRuntime: true
}
})Nuxt Content
Frontmatter:
---
ogImage:
component: OgImageBlog
props:
author: John Doe
---With asSeoCollection() (see main SKILL.md):
<script setup>
const { data: page } = await useAsyncData(() => queryCollection('posts').path(route.path).first())
if (page.value?.ogImage)
defineOgImage(page.value.ogImage)
</script>Debug
- Preview:
/__og-image__/image/[path]/og.png - Inspector: Enable
ogImage: { debug: true }in config
Screenshots
Capture page as OG image (requires Chromium):
defineOgImageScreenshot({
colorScheme: 'dark',
mask: '.navigation, .footer',
selector: '.article-content'
})Route Rules
export default defineNuxtConfig({
routeRules: {
'/blog/**': { ogImage: { component: 'OgImageBlog' } },
'/admin/**': { ogImage: false }
}
})Deployment
Community templates are dev-only. Before deploying, eject:
npx nuxt-og-image eject NuxtSeoSchema.org Structured Data
JSON-LD structured data for rich search results.
Site Identity
Configure once in nuxt.config.ts:
import { defineOrganization } from 'nuxt-schema-org/schema'
export default defineNuxtConfig({
schemaOrg: {
identity: defineOrganization({
name: 'My Company',
url: 'https://example.com',
logo: '/logo.png',
sameAs: ['https://twitter.com/mycompany', 'https://github.com/mycompany']
})
}
})For personal sites:
import { definePerson } from 'nuxt-schema-org/schema'
export default defineNuxtConfig({
schemaOrg: {
identity: definePerson({
name: 'John Doe',
url: 'https://johndoe.com',
image: '/avatar.jpg',
sameAs: ['https://twitter.com/johndoe']
})
}
})Page-Level Schema
Define functions are auto-imported in components (no import needed):
// Article page
useSchemaOrg([
defineArticle({
headline: 'My Article Title',
description: 'Article description',
image: '/article-image.jpg',
datePublished: '2025-01-15',
dateModified: '2025-01-20',
author: { name: 'John Doe', url: 'https://johndoe.com' }
})
])// Product page (include url in offers for Google validation)
useSchemaOrg([
defineProduct({
name: 'Product Name',
description: 'Product description',
image: '/product.jpg',
offers: {
price: 99.99,
priceCurrency: 'USD',
availability: 'InStock',
url: 'https://example.com/product'
}
})
])Define Functions
| Function | Use Case |
|---|---|
defineArticle() | Blog posts, news |
defineProduct() | E-commerce products |
defineFAQPage() | FAQ pages |
defineHowTo() | Tutorial/guide pages |
defineRecipe() | Recipe pages |
defineEvent() | Events |
defineLocalBusiness() | Business info |
defineVideo() | Video content |
defineBreadcrumb() | Breadcrumb navigation |
defineWebPage() | Generic page |
defineWebSite() | Site-wide (auto-added) |
defineJobPosting() | Job listings |
defineSoftwareApp() | Software/apps |
defineService() | Services |
Data Inference
Module auto-infers from page head:
title→ WebPage namedescription→ WebPage descriptionog:image→ WebPage image
Breadcrumbs
Auto-generated from route path, or customize:
useSchemaOrg([
defineBreadcrumb({
itemListElement: [
{ name: 'Home', item: '/' },
{ name: 'Blog', item: '/blog' },
{ name: 'My Post', item: '/blog/my-post' }
]
})
])Or use the useBreadcrumbItems() composable (from seo-utils):
const items = useBreadcrumbItems()
useSchemaOrg([defineBreadcrumb({ itemListElement: items })])FAQ Page
useSchemaOrg([
defineFAQPage({
mainEntity: [
{ name: 'What is your return policy?', acceptedAnswer: 'You can return within 30 days.' },
{ name: 'How do I contact support?', acceptedAnswer: 'Email us at support@example.com' }
]
})
])Nuxt Content
Frontmatter:
---
title: My Article
schemaOrg:
- type: BlogPosting
headline: My Article
datePublished: 2025-01-15
author:
type: Person
name: John Doe
---With asSeoCollection() (see main SKILL.md), ensure schema renders:
<script setup>
const { data: page } = await useAsyncData(() => queryCollection('posts').path(route.path).first())
useHead(page.value?.head || {})
</script>Debug & Validation
- Debug endpoint:
/__schema-org__/debug.jsonin dev - Config:
schemaOrg: { debug: true } - Google Rich Results Test
- Schema.org Validator
Route Rules
export default defineNuxtConfig({
routeRules: {
'/blog/**': {
schemaOrg: { type: 'Article' }
}
}
})Site Config
Foundation module providing shared configuration for all SEO modules.
Configuration
// nuxt.config.ts
export default defineNuxtConfig({
site: {
url: 'https://example.com', // Required for absolute URLs
name: 'My Site', // Site name (used in titles, schema)
description: 'Site description', // Default meta description
defaultLocale: 'en', // Default language
indexable: true, // Allow search engine indexing
trailingSlash: false, // URL trailing slash preference
}
})Environment-Based Indexing
Control indexing per environment using NUXT_SITE_* env vars:
# .env.production
NUXT_SITE_URL=https://example.com
NUXT_SITE_ENV=production
# .env.staging
NUXT_SITE_URL=https://staging.example.com
NUXT_SITE_ENV=stagingThe module auto-detects env and sets indexable: false for non-production environments.
For explicit control:
export default defineNuxtConfig({
site: {
url: process.env.NUXT_SITE_URL,
// Explicit: only index when explicitly set to 'true'
indexable: process.env.NUXT_SITE_INDEXABLE === 'true'
}
})Note: !== 'false' defaults to true when env var is undefined - use === 'true' for fail-safe behavior.
Runtime Access
const site = useSiteConfig()
console.log(site.url, site.name, site.description)Works in components, composables, and server routes.
i18n Integration
Automatically integrates with @nuxtjs/i18n:
export default defineNuxtConfig({
site: {
url: 'https://example.com',
defaultLocale: 'en',
},
i18n: {
locales: [
{ code: 'en', language: 'en-US' },
{ code: 'fr', language: 'fr-FR' },
]
}
})Locale-specific overrides in site object:
site: {
name: 'My Site',
locales: {
fr: { name: 'Mon Site' }
}
}Override Per-Page
Use route rules for page-specific config:
export default defineNuxtConfig({
routeRules: {
'/admin/**': { site: { indexable: false } },
'/fr/**': { site: { name: 'Mon Site', defaultLocale: 'fr' } }
}
})SEO Utilities
Additional utilities from nuxt-seo-utils and nuxt-link-checker.
Canonical URLs
Automatic canonical URLs based on site config.
export default defineNuxtConfig({
seoUtils: {
canonicalQueryWhitelist: ['page', 'sort'], // Keep these query params
redirectToCanonicalSiteUrl: true // 301 to canonical domain
}
})Override per-page:
useHead({
link: [{ rel: 'canonical', href: 'https://example.com/preferred-url' }]
})Breadcrumbs
Generate breadcrumb items from current route:
const items = useBreadcrumbItems()
// [{ label: 'Home', to: '/' }, { label: 'Blog', to: '/blog' }, { label: 'My Post' }]For schema.org integration, see schema-org.md.
Render in template:
<template>
<nav aria-label="Breadcrumb">
<ol class="flex gap-2">
<li v-for="(item, i) in items" :key="i">
<NuxtLink v-if="item.to" :to="item.to">{{ item.label }}</NuxtLink>
<span v-else>{{ item.label }}</span>
</li>
</ol>
</nav>
</template>Customize labels in route meta:
// pages/blog/[slug].vue
definePageMeta({
breadcrumb: { label: 'Article' }
})Title Templates
Set site-wide title template:
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
titleTemplate: '%s | My Site'
}
}
})Override per-page:
useHead({
title: 'Page Title',
titleTemplate: '%s - Different Template'
})Meta Defaults
// nuxt.config.ts
export default defineNuxtConfig({
app: {
head: {
meta: [
{ name: 'author', content: 'My Name' },
{ property: 'og:site_name', content: 'My Site' }
]
}
}
})Link Checker
Build-time validation of links.
export default defineNuxtConfig({
linkChecker: {
failOnError: true, // Default: fail build on errors
exclude: ['/api/**'],
skipInspections: ['missing-hash'],
report: { html: true } // Generate HTML report
}
})Inspections:
no-error-response- 404/500 errorsno-baseless- Missing base URLno-javascript- javascript: linkstrailing-slash- Inconsistent slashesmissing-hash- Invalid anchor targetsno-uppercase-chars- URL casingabsolute-site-urls- Hardcoded domain
Ignoring Links
<a href="/maybe-broken" data-link-checker-ignore>Link</a>File-Based Icons
Place favicon files in public/:
public/
├── favicon.ico
├── favicon.svg # Modern browsers
├── apple-touch-icon.png
└── site.webmanifestAuto-detected and added to <head>.
For SVG favicon with dark mode support:
<!-- public/favicon.svg -->
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
<style>
path { fill: #000; }
@media (prefers-color-scheme: dark) {
path { fill: #fff; }
}
</style>
<path d="..."/>
</svg>Social Meta Tags
Automatic Open Graph and Twitter cards from site config (see site-config.md).
Override per-page:
useSeoMeta({
title: 'Page Title',
description: 'Page description',
ogImage: '/images/page-og.png',
twitterCard: 'summary_large_image'
})Trailing Slash Redirect
Enforce consistent URLs:
export default defineNuxtConfig({
site: {
trailingSlash: false // Redirect /blog/ to /blog
}
})Debug Panel
Enable comprehensive debug panel:
export default defineNuxtConfig({
seo: { debug: true }
})Shows in dev:
- Current meta tags
- Schema.org data
- OG image preview
- Sitemap/robots status
Related skills
How it compares
Use nuxt-seo for Nuxt-native robots and sitemap modules; use framework-agnostic SEO skills for non-Nuxt stacks.
FAQ
Should I load all reference files?
No. Load only the file matching your task to keep token usage low.
How does Nuxt Content integrate?
Use asSeoCollection in content.config.ts and load @nuxtjs/seo before @nuxt/content.
Which modules are included?
nuxt-site-config, robots, sitemap, og-image, schema-org, seo-utils, and link-checker.
Is Nuxt Seo safe to install?
skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.