Introduction
Nuxt SEO v6 moves every bundled module to a new major version. AI Ready and Skew Protection join the bundle. For the full list of changes, see the v6 release notes.
- First upgrade to Nuxt 4.6.1 or later, and Node 22.22.3+, 24.15.0+, or 26+. Nuxt 3 sites stay on Nuxt SEO v5.
- Remove
nuxt-ai-readyandnuxt-skew-protectionfrommodules.@nuxtjs/seoinstalls them. - If OG Image signs URLs, set
NUXT_APP_SECRETin production. Without it, production pages return a 500 error. - Update or remove each bundled module that you pinned. An older pinned module now fails the build.
- Add
nuxtseo-devtools-hostas a development dependency to keep the SEO DevTools panels.
| Module | v5 | v6 |
|---|---|---|
nuxt-site-config | v4 | v5 |
@nuxtjs/robots | v6 | v7 |
@nuxtjs/sitemap | v8 | v9 |
nuxt-og-image | v6 | v7 |
nuxt-schema-org | v6 | v7 |
nuxt-seo-utils | v8 | v9 |
nuxt-link-checker | v5 | v6 |
nuxt-ai-ready | not bundled | v3 |
nuxt-skew-protection | not bundled | v2 |
Support
If you get stuck with the migration or have post-migration bugs, please get in touch.
Step 1: Update Nuxt and Node
Nuxt 4.6.1 or later
Nuxt SEO v6 requires Nuxt ^4.6.1 || ^5.0.0. Nuxt SEO v6 does not support Nuxt 3. If your site runs Nuxt 3, stay on Nuxt SEO v5.
Upgrade Nuxt before you upgrade Nuxt SEO:
npx nuxt upgradeNode 22.22.3+, 24.15.0+, or 26+
Node must match ^22.22.3 || ^24.15.0 || >=26.0.0. Check engines in your package.json, your .nvmrc, and the Node versions in CI and in your deployment.
Step 2: Update Nuxt SEO
npx nypm add @nuxtjs/seo@^6Remove AI Ready and Skew Protection from modules
@nuxtjs/seo now installs AI Ready and Skew Protection. Remove both from your modules array and from your dependencies. Keep your options under the aiReady and skewProtection keys.
export default defineNuxtConfig({
modules: [
'@nuxtjs/seo',
- 'nuxt-ai-ready',
- 'nuxt-skew-protection',
],
})To turn either module off, set its key to false:
export default defineNuxtConfig({
modules: ['@nuxtjs/seo'],
aiReady: false,
skewProtection: false,
})If you keep both modules, your site gets new public output:
- AI Ready serves
/llms.txtand a Markdown version of every page. A prerender also writes/llms-full.txt. AI Ready publishes Agent Skills frompublic/skills/<name>/SKILL.md. It generates an API catalog when you configure an MCP server and a site URL. - Skew Protection keeps the assets of earlier builds after a deploy. Nuxt SEO sets
updateStrategy: 'polling'andcookie: false, so it polls Nuxt's app manifest and sets no version cookie.
node_modules/.cache/nuxt-seo/skew-protection by default. If your CI starts from a clean checkout, cache that directory between builds, or set skewProtection.storage. Otherwise each deploy loses the assets of earlier builds.If a server handler calls isClientOutdated(), set skewProtection.cookie to a cookie config object.
If you already used Skew Protection
Skew Protection v2 changes these defaults:
- An unset
updateStrategynow means hourly polling on every platform. For instant updates, setupdateStrategy: 'sse'or'ws'. experimental.appManifest: falsenow fails setup.- The default storage driver is
fs-lite. An explicitdriver: 'fs'still works. - With
multiTab: true, tabs share one push connection. To keep one connection per tab, setmultiTab: falseorconnectionTracking: true.
If you already used AI Ready
AI Ready v3 negotiates Markdown from the Accept header only. AI bots no longer get Markdown from their User-Agent alone. To restore that, set botNegotiation:
export default defineNuxtConfig({
aiReady: {
botNegotiation: true,
},
})AI Ready v3 also drops the better-sqlite3 fallback and uses node:sqlite.
Update pinned module versions
If your package.json pins a bundled module, the pinned copy replaces the bundled one. An older pinned copy now fails the build and names the module:
ERROR [@nuxtjs/seo] Module `@nuxtjs/sitemap` version (`8.6.1`) does not satisfy `>=9.0.0` (requested by `@nuxtjs/seo`).Update each pin to the version in the table above, or remove the pin and let @nuxtjs/seo install the module:
{
"dependencies": {
"@nuxtjs/seo": "^6.0.0",
- "@nuxtjs/sitemap": "^8.6.1"
+ "@nuxtjs/sitemap": "^9.0.0"
}
}If you cannot find the pin, run pnpm why <package>. If you use @nuxtjs/i18n, it must be v10 or later.
Install the DevTools host
The SEO DevTools panels now live in an optional package. If you use them, add the host as a development dependency, then restart Nuxt:
npx nypm add -D nuxtseo-devtools-hostIf the host is missing, each panel shows an install button.
Check nuxtseo: false
In v5, nuxtseo: false type checked but installed every module anyway. In v6, it installs none of the bundled modules. If your config sets it, remove it to keep the modules. A module that you add to modules yourself still installs.
Step 3: Set NUXT_APP_SECRET for OG Image
OG Image v7 signs image URLs with Nuxt's application secret. If URL signing is on, set NUXT_APP_SECRET to a value of at least 32 characters. Without it, production image and page requests return a 500 error.
Generate a secret:
npx nuxt-og-image generate-secretSet it in your deployment environment, and in .env for local runs:
NUXT_APP_SECRET=<your-secret>Remove the OG Image secret from your config:
export default defineNuxtConfig({
ogImage: {
- security: {
- secret: process.env.NUXT_OG_IMAGE_SECRET,
- },
},
})NUXT_OG_IMAGE_SECRET still works with a deprecation warning. Signed URLs from OG Image v6 become invalid, so rebuild prerendered pages and purge cached HTML that contains them. Fully static sites do not need a secret.
In development, the setup checks report a missing secret as required.
Other OG Image v7 changes
The OG Image v7 migration guide covers each of these changes:
- OG Image needs Satori 0.47. Add
flex flex-colto elements that depended on the old forced flex layout. - OG Image needs Takumi v2 (
^2.15.0). Replacetakumi.fetchedResourcesandtakumi.persistentImageswithtakumi.images. - Custom fonts need
@nuxt/fontsv1. Families used only in OG images needglobal: true.
Step 4: Update Nuxt Content
Use Nuxt Content v3
Nuxt SEO v6 no longer supports Nuxt Content v2. Upgrade to Nuxt Content v3. See the Nuxt Content guide for the collection setup.
Upgrade to Zod 4
defineRobotsSchema(), defineSitemapSchema(), and defineOgImageSchema() require Zod 4. Upgrade the zod package in your app:
npx nypm add zod@^4Replace asSeoCollection()
v5 deprecated asSeoCollection(). v6 removes it. Compose the schema helpers in your collection schema:
import { defineCollection, defineContentConfig } from '@nuxt/content'
- import { asSeoCollection } from '@nuxtjs/seo/content'
+ import { defineOgImageSchema, defineRobotsSchema, defineSchemaOrgSchema, defineSitemapSchema } from '@nuxtjs/seo/content'
+ import { z } from 'zod'
export default defineContentConfig({
collections: {
content: defineCollection(
- asSeoCollection({
- type: 'page',
- source: '**/*.md',
- }),
+ {
+ type: 'page',
+ source: '**/*.md',
+ schema: z.object({
+ robots: defineRobotsSchema(),
+ sitemap: defineSitemapSchema(),
+ ogImage: defineOgImageSchema(),
+ schemaOrg: defineSchemaOrgSchema(),
+ }),
+ },
),
},
})Step 5: Update Server Code
Server hooks receive a RequestEvent
The robots:* and sitemap:* hook contexts now carry a RequestEvent from nuxt/server, in place of an h3 H3Event. Read request headers with the web API:
export default defineNitroPlugin((nitroApp) => {
nitroApp.hooks.hook('sitemap:sources', (ctx) => {
- const auth = ctx.event.node.req.headers.authorization
+ const auth = ctx.event.req.headers.get('authorization')
})
})OG Image's getOgImageUrl() also takes a RequestEvent. Import defineEventHandler from nuxt/server in handlers that call it.
Update runtime imports
Auto imports do not change. If you import a module's runtime by hand, use the new aliases:
| Old | New |
|---|---|
#internal/nuxt-robots, #internal/nuxt-simple-robots | #robots/server or #robots/app |
#schema-org | #schema-org/app or #schema-org/server |
#seo-utils | #seo-utils/app |
Step 6: Update Site Config
Site Config v5 changes priority and values:
updateSiteConfig()without_prioritynow ranks below yoursitekey andNUXT_SITE_*variables. Pass_priority: SiteConfigPriority.runtimeto keep the old order.indexableis now always a boolean. It defaults toenv === 'production'.- Module authors: Site Config v5 drops
installNuxtSiteConfig(). Declarenuxt-site-configinmoduleDependencies.
- import { updateSiteConfig } from 'nuxt-site-config-kit'
+ import { SiteConfigPriority, updateSiteConfig } from 'nuxt-site-config-kit'
updateSiteConfig({
url: 'https://example.com',
+ _priority: SiteConfigPriority.runtime,
})Step 7: Check Smaller Module Changes
- Robots:
robots.txtfiles inassets/orpages/resolve fromsrcDir(app/in Nuxt 4). Move a rootassets/robots.txtorpages/robots.txtunderapp/. - Robots:
noaiandnoimageairoute rules no longer mark a route as not indexable. Arobots:configchange made during a request now affects only that request. - Robots: route rules now take precedence over
definePageMeta({ robots }). If both set a rule for a page, the route rule wins. Check pages that set both. - Sitemap: Sitemap v9 drops
nuxt-simple-robotssupport. Use@nuxtjs/robotsv7. - Link Checker: Reports show the real status text, and an unreachable link reports status
0. - SEO Utils:
sharpis an optional peer dependency. Add it as a development dependency to usenuxt-seo-utils icons. Runtime minification no longer rewrites inline JavaScript.
Step 8: Verify
- Install dependencies and update the lockfile.
- Run
npx nuxt typecheck. - Run
npx nuxt build. A module version mismatch fails here and names the module. - Run
npx nuxt dev, open the home page, and read the Nuxt SEO setup checks in the terminal. - Check
/robots.txt,/sitemap.xml,/llms.txt, and one OG image URL.