Configuration
Set module options under aiReady in your Nuxt configuration. Defaults below describe the current module.
@nuxtjs/seo, set these options under the same aiReady key.export default defineNuxtConfig({
aiReady: {
// options
}
})enabled: boolean
- Default:
true
aiReady: {
enabled: process.env.NODE_ENV === 'production'
}debug: boolean
- Default:
false
Enable debug logging for module operations.
contentNegotiation: boolean
- Default: Automatic per route
Set false to keep original page URLs as HTML and disable Accept and bot negotiation.
Explicit .md URLs, alternate links, llms.txt, MCP, and page indexing remain available.
Default negotiation uses Accept only.
Automatic mode disables negotiation for ISR and for response caches without accept in cache.varies.
This includes swr rules after Nitro normalizes them.
headersOnly: true remains safe because it does not cache the response body.
If you enable bot negotiation, cache variation must also include sec-fetch-dest and user-agent.
To restore automatic mode, remove contentNegotiation; do not set it to 'auto'.
Set false for URL-only CDN or reverse proxy caching configured outside Nuxt. Set true to force negotiation and take responsibility for the cache key.
export default defineNuxtConfig({
aiReady: {
contentNegotiation: false
}
})botNegotiation: boolean
- Default:
false
Offer Markdown to recognized AI bots even when their Accept header prefers HTML.
Bot detection does not override browser navigation or explicit Markdown rejection.
contentNegotiation: false also disables bot negotiation.
This mode requires cache variation on Accept, Sec-Fetch-Dest, and User-Agent. Leave the default to avoid creating cache entries for each User-Agent value.
export default defineNuxtConfig({
aiReady: { botNegotiation: true },
routeRules: {
'/docs/**': {
cache: {
maxAge: 3600,
varies: ['accept', 'sec-fetch-dest', 'user-agent'],
},
},
},
})Merge these entries with existing cache options and variation headers. External CDN cache rules must also cover all three inputs.
apiCatalog: false | ApiCatalogConfig
- Default: Disabled until you configure entries or an integration generates them
- Nuxt SEO v6 keeps this default.
Publish an RFC 9727 API Catalog at /.well-known/api-catalog. Relative URLs resolve against site.url and app.baseURL once during module setup. Non-root apps redirect the origin-root request to the base-aware route.
export default defineNuxtConfig({
site: {
url: 'https://example.com',
},
aiReady: {
apiCatalog: {
entries: [{
anchor: '/api',
serviceDesc: {
href: '/openapi.json',
type: 'application/vnd.oai.openapi+json;version=3.1',
},
serviceDoc: { href: '/docs/api', type: 'text/html' },
status: { href: '/api/health', type: 'application/json' },
}],
},
},
})Each entry needs at least one relation target. A relation accepts one target or an array. Supported typed relations are item, serviceDesc, serviceDoc, serviceMeta, status, and apiCatalog. Use relations for other RFC 8288 relation names. Set apiCatalog: false to suppress configured and integration-generated entries.
mdreamOptions: MdreamOptions
- Default:
{ minimal: true, clean: true }
Configure mdream HTML-to-markdown conversion.
export default defineNuxtConfig({
aiReady: {
mdreamOptions: {
minimal: true
}
}
})markdownCacheHeaders: { maxAge?: number, swr?: boolean }
- Default:
{ maxAge: 3600, swr: true }
Cache settings for runtime markdown endpoints.
| Option | Type | Default | Description |
|---|---|---|---|
maxAge | number | 3600 | Cache duration in seconds |
swr | boolean | true | Stale-while-revalidate |
agentSkills: false | AgentSkillsConfig
- Default:
{} - Nuxt SEO v6 keeps this default.
Publish an Agent Skills Discovery v0.2.0 index.
The module finds public/skills/<name>/SKILL.md files in your project and its layers.
It honors each layer's configured public directory.
Set agentSkills.dir: 'skills' to publish root skills/ directories explicitly.
It serves each file at /.well-known/agent-skills/<name>/SKILL.md and /skills/<name>/SKILL.md.
For one skill, or the skill selected by root, it also serves /SKILL.md.
The module lists discovered skills in llms.txt. With no skills, it publishes nothing.
Use dir to change the folder or disable discovery. Use skills to add local or external entries.
Set llmsTxt: false to leave llms.txt alone, or agentSkills: false to disable publication.
The ai-ready:agent-skills hook sees every entry before publication.
aiReady: {
agentSkills: {
skills: [{
source: 'local',
name: 'seo-audit',
description: 'Audit a site for critical SEO issues.',
file: './skills/seo-audit/SKILL.md'
}]
}
}llmsTxt: LlmsTxtConfig | false
- Default: Auto-generated
Configure llms.txt generation.
Set false when an application route owns the file.
An existing public/llms.txt automatically disables generation.
export default defineNuxtConfig({
aiReady: {
llmsTxt: {
markdownLinks: true,
sections: [
{
title: 'API Reference',
links: [
{ title: 'REST API', href: '/docs/api', description: 'API docs' }
]
},
{
title: 'Debug Endpoints',
optional: true,
links: [
{ title: 'Debug Route', href: '/__ai-ready-debug', description: 'Internal debugging' }
]
}
],
notes: 'Built with Nuxt AI Ready'
}
}
})LlmsTxtSection:
| Property | Type | Description |
|---|---|---|
title | string | Section title |
description | string | string[] | Section context rendered in the heading-free preamble, or in each optional link note |
links | { title, href, description? }[] | Links in section |
optional | boolean | Put the section's links in the single ## Optional file list, which LLMs may skip with shorter context windows |
sitemap | string | string[] | Generate a separate file from named sitemaps, including their chunks |
path | string | Generated section file at /llms/<name>.txt. Defaults to /llms/<first sitemap>.txt |
LlmsTxtConfig:
| Property | Type | Description |
|---|---|---|
markdownLinks | boolean | Link automatically generated page and locale entries to available Markdown representations. Defaults to true |
directive | { markdown?: boolean, html?: boolean } | Point each page at llms.txt. markdown adds a line after the frontmatter of every .md response, default true. html adds a visually hidden link at the top of every HTML body, default false |
sections | LlmsTxtSection[] | Custom sections |
notes | string | string[] | Additional heading-free context rendered before file-list sections |
pages | 'sitemap' | 'all' | false | Default sitemap uses current sitemap admission. all includes stored pages outside the sitemap. false omits the automatic list |
sitemaps | string[] | Read only these sitemap names. Use sitemap for the default single sitemap. An empty array stops sitemap discovery |
maxLength | number | Maximum characters per file. Default 80000, minimum 1024. Large lists split into linked files |
llmsFullTxt: boolean
- Default:
true
Set false to omit /llms-full.txt, its runtime route, and its generated discovery link.
The setting also stops the streamed export during prerendering.
sitemapMd: boolean
- Default:
true
Generate a Markdown sitemap at /sitemap.md from indexed pages. The sitemap groups pages by top-level path segment under ## headings. Each link points at the page’s .md representation. When a page records a last update, it becomes the link's title text.
The same flag appends a ## Sitemap section to module-generated Markdown, linking back to /sitemap.md.
export default defineNuxtConfig({
aiReady: {
sitemapMd: false
}
})describedby: boolean
- Default:
true
Advertise llms.txt with rel="describedby" on HTML and Markdown responses. HTML pages get a <link rel="describedby" href="/llms.txt"> tag, and both variants get a Link header entry.
export default defineNuxtConfig({
aiReady: {
describedby: false
}
})contentSignal: false | { aiTrain?: boolean, contentUsage?: boolean, search?: boolean, aiInput?: boolean }
- Default:
undefined, which sendsContent-Signal: search=yes, ai-input=yes
Content Signal directives for robots.txt. See Content Signals guide.
Without this option, robots.txt allows search and AI input and states no AI training preference.
An object states the whole policy: the module sends no for each permission you leave out.
Set false to send no Content-Signal line.
export default defineNuxtConfig({
aiReady: {
contentSignal: {
aiTrain: false, // Block training
contentUsage: false, // Omit Content-Usage from robots.txt
search: true, // Allow search indexing
aiInput: true, // Allow RAG/grounding
}
}
})tools: SiteToolsConfig
Configure the three built-in tools once, then attach each one to MCP, WebMCP or both.
| Tool | Shared options | mcp options | webmcp options |
|---|---|---|---|
listPages | defaultLimit | enabled | enabled, maxOutputChars, exposedTo |
searchPages | defaultLimit | enabled | enabled, maxOutputChars, exposedTo |
getPageMarkdown | None | enabled | enabled, maxOutputChars, exposedTo |
defaultLimit defaults to 20 for listPages and 10 for searchPages. Values are clamped to 50. WebMCP output defaults to 1,500 characters per tool.
export default defineNuxtConfig({
aiReady: {
tools: {
listPages: {
defaultLimit: 10,
webmcp: { enabled: false },
},
searchPages: {
defaultLimit: 5,
webmcp: { maxOutputChars: 3000 },
},
},
},
})The module enables omitted attachment objects when their transport is active. Set mcp.enabled or webmcp.enabled to false on one tool to leave it off that transport.
mcp: { tools?: boolean, resources?: boolean }
- Default:
{ tools: true, resources: true }
Control MCP features when @nuxtjs/mcp-toolkit installed.
export default defineNuxtConfig({
aiReady: {
mcp: {
tools: true, // list_pages, search_pages, get_page_markdown
resources: true, // pages resource
}
}
})See MCP guide for tool/resource details.
mcpServerCard: false | McpServerCardConfig
- Default:
{ cacheMaxAge: 3600 }
Publish experimental SEP-2127 discovery metadata at <mcp-route>/server-card when MCP Toolkit runs on the server. For the default Toolkit route, the card is available at /mcp/server-card. The same card is also served at /.well-known/mcp/server-card.json and /.well-known/mcp.json, and llms.txt links it. Set this option to false to disable these routes and the llms.txt entry.
| Option | Type | Default | Description |
|---|---|---|---|
name | string | Derived from site host and MCP route | Reverse-DNS/server identity |
title | string | Existing Toolkit or site name | Human-readable server title |
description | string | Toolkit or site description | Server description, up to 100 characters |
websiteUrl | string | None | Absolute HTTP or HTTPS project or documentation URL |
cacheMaxAge | number | 3600 | Browser and shared cache lifetime in seconds |
Toolkit icons are copied into the card. The card route is omitted when Toolkit is absent, disabled or unavailable in a static deployment.
webmcp: boolean | WebMcpConfig
- Default:
false
Register WebMCP tools for browser agents through document.modelContext.
| Option | Type | Default | Description |
|---|---|---|---|
tools | boolean | true | Attach tools enabled under aiReady.tools |
exposedTo | string[] | None | Default trusted origins for built-in and composable tools. Same-origin only by default |
export default defineNuxtConfig({
aiReady: {
tools: {
listPages: {
webmcp: { enabled: false },
},
searchPages: {
defaultLimit: 20,
webmcp: { maxOutputChars: 3000 },
},
},
webmcp: {
exposedTo: ['https://agent.example.com'],
},
},
})Nuxt auto-imports useWebMcpTool() and useWebMcpSupported() when you enable WebMCP. Set webmcp.tools to false to register your own tools without the built-in definitions or /__ai-ready/pages endpoint.
llmsTxtCacheSeconds: number
- Default:
600(10 minutes)
Cache duration for llms.txt route handlers. Uses stale-while-revalidate.
export default defineNuxtConfig({
aiReady: {
llmsTxtCacheSeconds: 3600 // 1 hour
}
})database: false | { type?: string, filename?: string, bindingName?: string, url?: string, authToken?: string }
- Default: Disabled until a requested feature needs stored pages.
Configure the database for page storage. The module auto-detects the best driver based on the deployment platform.
The database needs drizzle-orm, an optional peer dependency: npx nypm add drizzle-orm@1.0.0-rc.4.
If the database is on and drizzle-orm is missing, the build fails. The error names the feature that turned on the database.
| Option | Type | Default | Description |
|---|---|---|---|
type | 'none' | 'sqlite' | 'bun' | 'd1' | 'libsql' | 'neon' | 'postgres' | 'sqlite' | Database type. 'none' disables the database |
filename | string | '.data/ai-ready/pages.db' | SQLite file path |
bindingName | string | 'DB' | D1 binding name |
url | string | - | LibSQL, Neon, or PostgreSQL URL |
authToken | string | - | LibSQL/Turso auth token |
export default defineNuxtConfig({
aiReady: {
database: {
filename: '.data/ai-ready/pages.db'
}
}
})export default defineNuxtConfig({
aiReady: {
database: {
type: 'd1',
bindingName: 'DB'
}
}
})export default defineNuxtConfig({
aiReady: {
database: {
type: 'libsql',
url: process.env.TURSO_URL,
authToken: process.env.TURSO_AUTH_TOKEN
}
}
})export default defineNuxtConfig({
aiReady: {
database: {
type: 'postgres',
url: process.env.DATABASE_URL
}
}
})export default defineNuxtConfig({
aiReady: {
database: false
}
})Driver auto-detection:
Every driver needs drizzle-orm. Some drivers also need a client package:
| Platform | Driver | Extra dependency |
|---|---|---|
| Node.js | node:sqlite | None |
| Bun | bun:sqlite | None |
| Cloudflare | D1 | None |
Vercel (with POSTGRES_URL) | Neon Postgres | @neondatabase/serverless |
database.type: 'libsql' | LibSQL | @libsql/client |
database.type: 'postgres' | PostgreSQL | postgres |
Each extra dependency is an optional peer dependency. Install it in the same command as drizzle-orm. For Neon: npx nypm add drizzle-orm@1.0.0-rc.4 @neondatabase/serverless.
The Neon and PostgreSQL drivers read database.url, POSTGRES_URL, then DATABASE_URL.
Prerendering creates a compressed dump. Before its first database query, each server process restores the dump into empty storage or checks it for build changes.
No Database
The database stays off when no requested feature needs stored pages.
Set database: false (or database: { type: 'none' }) to force it off.
No driver and no drizzle-orm code enter the server bundle, so the app does not need drizzle-orm.
Runtime indexing, MCP page tools or resources, and WebMCP page tools enable storage automatically. An explicit database config also enables storage.
Build-time generation still works. You keep:
llms.txtandllms-full.txt, written during prerender..mdtwins for every prerendered page.- The
Linkheaders, content signals, API Catalog and Agent Skills.
Runtime Markdown conversion remains available without a database when the deployment retains a server. A fully static deployment can only serve its generated files.
The following features need stored pages:
list_pages,search_pagesandget_page_markdown, for both MCP and WebMCP.- The MCP pages resource.
- Runtime
llms-full.txtneeds stored pages to include page bodies. Prerender the route for static output.
A disabled database conflicts with runtimeSync and cron.
If you set any of them, the build fails with a message naming the option.
Table naming:
The module uses these reserved table names:
ai_ready_pages: Main pages tableai_ready_pages_fts: FTS5 full-text search index_ai_ready_info: Schema version tracking
The prefixes separate these tables from unrelated application tables. Do not reuse the same table names for other data.
cron: boolean
- Default:
false
Enable the scheduled task that runs every 5 minutes. It automatically enables runtimeSync for background indexing.
export default defineNuxtConfig({
aiReady: {
cron: true
}
})Runtime sync authentication
Set Nuxt's private runtimeConfig.appSecret through NUXT_APP_SECRET, with at least 32 characters.
No module-specific secret configuration is needed. The legacy runtimeSyncSecret option and environment keys remain supported with deprecation warnings.
AI Ready uses Nuxt's deriveSecret('nuxt-ai-ready:runtime-sync') to produce its bearer token.
OG Image uses the same root secret with its own purpose. The tokens are distinct.
Cloudflare requests derive the same token from their NUXT_APP_SECRET binding when available.
pnpm exec nuxt-ai-ready tokenSend this output in the Authorization: Bearer <token> header. Never send the root secret.
Status requests also authenticate; prune dry runs are the exception.
Without a root or legacy token, protected endpoints return 500. Invalid application secrets also return 500.
Missing or incorrect bearer tokens return 401.
Legacy ?secret= authentication remains supported with a deprecation warning. Prefer the Authorization header.
Nuxt generates a development root secret. Production builds do not generate one.
runtimeSyncSecret: string
Deprecated. Use NUXT_APP_SECRET for new deployments.
Existing aiReady.runtimeSyncSecret values and NUXT_AI_READY_RUNTIME_SYNC_SECRET remain supported as raw bearer tokens.
Cloudflare also accepts the legacy NUXT_NUXT_AI_READY_RUNTIME_SYNC_SECRET binding.
The module logs a deprecation warning when you configure or use a legacy token.
A non-empty appSecret always takes precedence. An invalid application secret fails without using the legacy token.
If you keep the legacy configuration, existing scheduler tokens work unchanged until you configure an application secret.
runtimeSync: boolean | { ttl?: number, batchSize?: number, pruneTtl?: number }
- Default:
false
Enable runtime controls and sitemap seeding for content that changes between deployments.
Set true for defaults, or use an object to change them.
Poll and cron process pending pages. TTL expiry alone does not mark an already indexed page pending. When a published page changes between builds, call the authenticated reindex endpoint or a manual indexing utility.
| Option | Type | Default | Description |
|---|---|---|---|
ttl | number | 3600 | Freshness window for manual indexing and sitemap refresh interval (seconds) |
batchSize | number | 50 | Pages per batch (max: 50) |
pruneTtl | number | 0 | Prune routes not seen in the sitemap for this many seconds (0 = disabled) |
export default defineNuxtConfig({
aiReady: {
runtimeSync: {
ttl: 3600,
batchSize: 20,
pruneTtl: 604800 // prune after 7 days
},
cron: true // enable scheduled indexing
}
})When enabled:
GET /__ai-ready/status: Check indexing progressPOST /__ai-ready/poll: Trigger batch indexing (requiresAuthorization: Bearer <token>header)POST /__ai-ready/prune: Prune stale routes (requiresAuthorization: Bearer <token>header)POST /__ai-ready/reindex?route=/about- Reindex a single route (requiresAuthorization: Bearer <token>header)
See Runtime Sync guide for details.
autoI18n: boolean
- Default:
true
Auto-detect @nuxtjs/i18n (or nuxt-i18n-micro) at build time and integrate locale data into:
llms.txt: adds an## Available Languages on Websitefile-list section linking to every locale rootLinkheaders: emitsLink: <…>; rel="alternate"; hreflang="…"per locale on.mdand HTML responses (RFC 8288)- Frontmatter: runtime HTML-to-Markdown responses include a
localefield - Database: each indexed page persists its
localefor filtered queries - FTS5 tokenizer: auto-switches to
trigramfor CJK locales (zh / ja / ko)
Disable to skip the integration even with an i18n module present:
export default defineNuxtConfig({
aiReady: {
autoI18n: false
}
})See i18n guide for details.
contentSource: boolean
- Default:
true
Read Markdown directly from page collections in @nuxt/content v3 or @harlan-zw/comark-content when available.
Set false to convert rendered HTML instead. Use that when a page’s meaning depends on its rendered components.
See Markdown Conversion for source lookup behavior.
prerender: { concurrency?: number }
- Default concurrency:
10
Control how many pages the module processes concurrently during prerendering. Set 1 to process one page at a time.
export default defineNuxtConfig({
aiReady: {
prerender: { concurrency: 5 },
},
})debugCron: boolean
- Default:
false
Record cron runs in the database for diagnostics. Enable it when investigating scheduled indexing. This option does not enable cron itself.