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, OG image requests return a 500 error. Pages still render. - 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 |
Coding-agent upgrade prompt
Copy this prompt into your coding agent. Every module also ships an Agent Skill. Get the Nuxt SEO Skill.
Copy the upgrade prompt
# Upgrade Guide: @nuxtjs/seo v5 to v6
Upgrade @nuxtjs/seo from v5 to v6 in this Nuxt project.
Scan each pattern below; show a diff per change.
## Requirements
- Nuxt 4.6.1 or later (Nuxt 3 is not supported). Run `npx nuxt upgrade` first.
- Node ^22.22.3 || ^24.15.0 || >=26.0.0. Check `engines`, `.nvmrc`, and CI Node versions.
## 1. Bundled modules
@nuxtjs/seo v6 installs nuxt-ai-ready and nuxt-skew-protection.
- Search: `nuxt-ai-ready`, `nuxt-skew-protection` in nuxt.config.* modules and package.json.
Remove their `modules` entries and dependencies; keep `aiReady` / `skewProtection` options.
- To disable either, set `aiReady: false` or `skewProtection: false`.
- Cache node_modules/.cache/nuxt-seo/skew-protection in CI; Skew Protection stores assets there.
- Skew Protection v2: unset `updateStrategy` now means polling; `experimental.appManifest: false` throws.
- AI Ready v3: bots no longer get Markdown by User-Agent. Set `aiReady: { botNegotiation: true }` to keep it.
## 2. Pinned module versions
Minimums: @nuxtjs/robots 7, @nuxtjs/sitemap 9, nuxt-og-image 7, nuxt-schema-org 7,
nuxt-seo-utils 9, nuxt-link-checker 6, nuxt-site-config 5, nuxt-ai-ready 3,
nuxt-skew-protection 2, @nuxtjs/i18n 10. Update or remove older pins in package.json.
## 3. DevTools
If the project uses Nuxt DevTools, add `nuxtseo-devtools-host` as a dev dependency.
## 4. OG Image v7
- Search: `security.secret`, `NUXT_OG_IMAGE_SECRET`, `ogImage.secret`.
Remove `security.secret`; set `NUXT_APP_SECRET` (32+ chars) in the deploy environment.
- Search: `*.satori.vue` and components in `components/OgImage/`.
If an element relied on forced flex layout, add `flex flex-col` classes.
- Search: `fetchedResources`, `persistentImages`. Replace with `takumi.images`.
- Search: `"@takumi-rs/core"`, `"satori"`, `"@nuxt/fonts"`. Need ^2.15.0, ^0.47.1, >=1.0.0.
- Full guide: https://nuxtseo.com/docs/og-image/migration-guide/v7
## 5. Zod 4
Search: `defineRobotsSchema`, `defineSitemapSchema`, `defineOgImageSchema`, `"zod"`.
Upgrade zod to ^4; fix [Zod](https://zod.dev) 3 API usage in content.config.ts.
## 6. Server hooks and events
Search: `sitemap:`, `robots:` hook handlers, `event.node.req`, `H3Event`, `getOgImageUrl(`.
- Hook contexts now carry a `RequestEvent` from `nuxt/server`.
Before: `ctx.event.node.req.headers.authorization`
After: `ctx.event.req.headers.get('authorization')`{lang="ts"}
- Handlers that call `getOgImageUrl` import `defineEventHandler` from `nuxt/server`.
## 7. Site Config v5
- Search: `updateSiteConfig(`. Without `_priority` it now ranks below the `site` key and env vars.
If you need its old overrides, add `_priority: SiteConfigPriority.runtime`.
- Search: `indexable === undefined`, `indexable == null`. `indexable` is always a boolean now.
- Search: `installNuxtSiteConfig`. Replace with a `moduleDependencies` entry for nuxt-site-config.
## 8. Smaller changes
- `#internal/nuxt-robots`, `#internal/nuxt-simple-robots` -> `#robots/server` or `#robots/app`.
- Bare `#schema-org` -> `#schema-org/app`; bare `#seo-utils` -> `#seo-utils/app`.
- `nuxt-simple-robots`, `nuxt-simple-sitemap`: remove; use @nuxtjs/robots and @nuxtjs/sitemap.
- `@nuxt/content` v2: Nuxt SEO v6 no longer supports it. Upgrade to Content v3.6 or later.
- `nuxt-seo-utils icons`: add `sharp` as a dev dependency.
- `assets/robots.txt` or `pages/robots.txt` at the root: move under `srcDir` (`app/`).
## Verify
1. Install dependencies and update the lockfile.
2. `npx nuxt typecheck`
3. `npx nuxt build`. A module version mismatch fails here with a named module.
4. `npx nuxt dev`, open the home page, and read the Nuxt SEO setup checks in the terminal.
5. Check /robots.txt, /sitemap.xml, /llms.txt, and one OG image URL.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.
With future.compatibilityVersion: 5
If you set future.compatibilityVersion: 5 and app.config.ts calls defineAppConfig(), you need @nuxtjs/sitemap 9.0.3 or later and nuxt-seo-utils 9.0.1 or later. Earlier v6 releases fail with this error:
ERROR defineAppConfig is not definedSitemap fails the build. SEO Utils with redirectToCanonicalSiteUrl builds, but the server fails when it starts. Refresh your lockfile so it resolves the fixed versions.
If you cannot upgrade yet, turn Nitro auto-imports back on:
export default defineNuxtConfig({
experimental: {
nitroAutoImports: true,
},
})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.1` (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.1"
}
}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 OG image requests return a 500 error. Pages still render.
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.