@nuxtjs/seo
Tested against @nuxtjs/seo 5.3.16 plus the fixes from harlan-zw/nuxt-seo#633 and #634, on Nuxt 4.5.2.
The package declares Nuxt moduleDependencies, and Nuxt installs each submodule. Its only runtime code checks the Nuxt version and the version of each loaded submodule.
Every option, composable, and component comes from a submodule. Docs: https://nuxtseo.com/docs/nuxt-seo
This Skill covers only what the bundle adds. For one module, use its own Skill or docs (table below).
Setup
export default defineNuxtConfig({
modules: ['@nuxtjs/seo'],
site: {
url: 'https://example.com',
name: 'My Site',
},
})- Add only
@nuxtjs/seotomodules. Do not also list the submodules; Nuxt installs each one once. - Set
site.urlandsite.name. Since v5, site config does not infer them frompackage.json. - If the app keeps OG images, install a renderer. See the first trap.
Which module owns which option
The meta module has one option, nuxtseo.enabled. Every other top level key belongs to one submodule.
| Key | Package | Reference |
|---|---|---|
site |
nuxt-site-config |
skilld.dev/gh/harlan-zw/nuxt-site-config |
robots |
@nuxtjs/robots |
https://nuxtseo.com/docs/robots |
sitemap |
@nuxtjs/sitemap |
https://nuxtseo.com/docs/sitemap |
ogImage |
nuxt-og-image |
https://nuxtseo.com/docs/og-image |
schemaOrg |
nuxt-schema-org |
skilld.dev/gh/harlan-zw/nuxt-schema-org |
seo |
nuxt-seo-utils |
skilld.dev/gh/harlan-zw/nuxt-seo-utils |
linkChecker |
nuxt-link-checker |
skilld.dev/gh/harlan-zw/nuxt-link-checker |
The seo key configures nuxt-seo-utils, not the bundle.
nuxtseo: false or nuxtseo: { enabled: false } installs no bundled submodule. See "Disable a submodule".
Automatic behaviour
With only site.url and site.name set, a production build gives:
/robots.txtthat allows all and links the sitemap, plus<meta name="robots">on each page (robots)./sitemap.xmlwith every static route (sitemap).- Title template
%s | My Site, canonical link,og:url,og:site_name, andog:titleandog:descriptioninferred from the page (SEO utils). - A JSON-LD graph with
WebSiteandWebPage(Schema.org). - In dev,
/robots.txtdisallows all crawlers. Check indexing on a production build. - A link check that runs on prerender (
nuxt generateor prerendered routes). A plainnuxt builddoes not run it.
Disable a submodule
Set the submodule key to false, or set enabled: false in it:
export default defineNuxtConfig({
modules: ['@nuxtjs/seo'],
site: { url: 'https://example.com', name: 'My Site' },
ogImage: false,
linkChecker: { enabled: false },
})false skips the module setup. enabled: false runs a setup that registers nothing. Both remove the routes, tags, and output of that module.
You cannot disable site. The other submodules need it.
To drop the whole bundle, set nuxtseo: false, or remove @nuxtjs/seo from modules. A submodule that you list in modules yourself still installs.
Add a standalone module
nuxt-ai-ready and nuxt-skew-protection are optional dependencies of the bundle. Installing the package is not enough; add it to modules:
export default defineNuxtConfig({
modules: ['@nuxtjs/seo', 'nuxt-ai-ready'],
})Nuxt Content v3
Import the four schema helpers from @nuxtjs/seo/content.
With pnpm, a direct import from @nuxtjs/robots/content fails with ERR_MODULE_NOT_FOUND, because the submodules are not top level dependencies.
Add zod to the app dependencies. The helpers import zod as an optional peer, and without it the import fails.
import { defineCollection, defineContentConfig } from '@nuxt/content'
import { defineOgImageSchema, defineRobotsSchema, defineSchemaOrgSchema, defineSitemapSchema } from '@nuxtjs/seo/content'
import { z } from 'zod'
export default defineContentConfig({
collections: {
content: defineCollection({
type: 'page',
source: '**/*.md',
schema: z.object({
robots: defineRobotsSchema(),
sitemap: defineSitemapSchema(),
ogImage: defineOgImageSchema(),
schemaOrg: defineSchemaOrgSchema(),
}),
}),
},
})schemaOrg and sitemap frontmatter apply without page code.
robots frontmatter applies only if the page passes page.seo to useSeoMeta():
<script setup lang="ts">
const route = useRoute()
const { data: page } = await useAsyncData(`page-${route.path}`, () => queryCollection('content').path(route.path).first())
useSeoMeta(page.value?.seo || {})
</script>The order of @nuxtjs/seo and @nuxt/content in modules does not change the output.
Breaking change in v5: asSeoCollection() is deprecated and warns at build. Old: defineCollection(asSeoCollection({ ... })). New: the schema above.
Traps
- In an Agent shell, a fresh install fails
nuxt build.nuxt-og-imagedefaults to the takumi renderer and throwstakumi renderer missing dependencies: @takumi-rs/core. It detects the Agent from environment variables such asCLAUDECODEandAI_AGENT. Outside an Agent it only logs the error, and the build passes. Fix: add@takumi-rs/coreto the app, or setogImage: false. - In an Agent shell,
nuxt devtries to install@takumi-rs/coreinto the app. If the install fails, the dev server exits. Decide on OG images before the first dev run. - A submodule in the app
package.jsonreplaces the bundled copy. Nuxt loads the app copy. If it is older than the bundle requires, the build stops with[@nuxtjs/seo] Module @nuxtjs/sitemap version (7.3.1) does not satisfy >=7.4 (requested by @nuxtjs/seo).Upgrade the pin or remove it. @nuxtjs/i18nbelow v10 fails every build. The error isModule @nuxtjs/i18n version (9.x) does not satisfy >=10.0 (requested by @nuxtjs/seo). Upgrade i18n.- Content
robots: 'noindex'keeps the page in the sitemap. Onlyrobots: falseremoves it from/sitemap.xml. Both rendernoindex, nofollow.
Version limits
- Nuxt 3.19 or later, or Nuxt 4.1 or later. Earlier Nuxt ignores
moduleDependencies, so the build stops with[@nuxtjs/seo] Nuxt 4.0.3 does not install module dependencies, so no Nuxt SEO module would load. Upgrade Nuxt to ^3.19.0 || >=4.1.0.Upgrade Nuxt. - v5 moved every submodule up one major, except OG image. Migration: https://nuxtseo.com/docs/nuxt-seo/migration-guide/v4-to-v5
Debug
- If a version error names a submodule, run
pnpm why <package>to find what pins the older copy.