Most sites don't need this. Prerendering handles page indexing automatically. Runtime sync is only needed for sites with frequently changing content that can't be prerendered.
Enable runtime sync if your site has:
If your content only changes on deploy, stick with prerendering—it's faster and simpler.
┌─────────────────────────────────────────────────────────────┐
│ Default: Prerendering (source of truth) │
│ Build time → crawl sitemap → create SQLite → compress │
│ Cold start → restore dump → llms.txt works immediately! │
├─────────────────────────────────────────────────────────────┤
│ Opt-in: Runtime Sync (for dynamic content) │
│ Cold start → restore dump → sitemap seeder → poll │
│ Cron (optional) → background re-indexing of stale pages │
└─────────────────────────────────────────────────────────────┘
export default defineNuxtConfig({
aiReady: {
runtimeSync: {
ttl: 3600, // Re-index pages & refresh sitemap older than 1 hour
batchSize: 20, // Pages per batch
pruneTtl: 0 // Prune routes not in sitemap (0 = never)
},
cron: true // Optional: scheduled background indexing (every minute)
}
})
runtimeSyncSecret is auto-generated when runtimeSync or cron is enabled. Set NUXT_AI_READY_RUNTIME_SYNC_SECRET env var to use your own.When runtimeSync is enabled, these endpoints are available:
# Check indexing progress
GET /__ai-ready/status
# Returns: { total: 50, indexed: 45, pending: 5 }
# Trigger batch indexing
POST /__ai-ready/poll?secret=<token>
# Returns: { indexed: 20, remaining: 25, errors: [], duration: 1234, complete: false }
# Process all pending pages (with timeout)
POST /__ai-ready/poll?secret=<token>&all=true&timeout=30000
# Returns: { indexed: 45, remaining: 0, errors: [], duration: 28500, complete: true }
# Prune stale routes (dry run - preview what would be pruned)
POST /__ai-ready/prune?dry=true&ttl=604800
# Returns: { routes: ["/old-page"], count: 1, ttl: 604800, dry: true }
# Prune stale routes (execute)
POST /__ai-ready/prune?secret=<token>&ttl=604800
# Returns: { pruned: 1, ttl: 604800, dry: false }
The secret query param is required for POST endpoints if runtimeSync.secret is configured.
| Param | Type | Default | Description |
|---|---|---|---|
limit | number | 10 | Max pages per batch (max: 50) |
all | boolean | false | Process until complete |
timeout | number | 30000 | Max ms for all mode |
secret | string | — | Auth token if configured |
| Param | Type | Default | Description |
|---|---|---|---|
dry | boolean | false | Preview stale routes without deleting |
ttl | number | pruneTtl config | Prune routes older than this (seconds) |
secret | string | — | Auth token (required unless dry run) |
When cron: true, automatic background indexing is enabled via Nitro scheduled tasks (runs every minute):
export default defineNuxtConfig({
aiReady: {
cron: true // Runs every minute, auto-enables runtimeSync
}
})
The module auto-enables nitro.experimental.tasks when cron is configured.
GET /__ai-ready/cron?secret=<token>. See the Cloudflare guide for details.| Option | Default | Description |
|---|---|---|
ttl | 3600 | Re-index pages & refresh sitemap older than this (seconds) |
pruneTtl | 0 | Delete routes not in sitemap for this long (0 = never) |
Force re-index regardless of TTL:
await indexPage('/about', html, { force: true })
The module uses SQLite via db0 for cross-platform support. It auto-detects the best connector:
| Runtime | Connector |
|---|---|
| Bun | bun:sqlite |
| Node.js 22.5+ | node:sqlite |
| Node.js <22.5 | better-sqlite3 |
For edge deployments, configure D1 or LibSQL:
export default defineNuxtConfig({
aiReady: {
database: {
type: 'd1',
bindingName: 'AI_READY_DB'
}
}
})
export default defineNuxtConfig({
aiReady: {
database: {
type: 'libsql',
url: process.env.TURSO_URL,
authToken: process.env.TURSO_AUTH_TOKEN
}
}
})
For serverless platforms (Vercel, Netlify, Lambda), the database is ephemeral. The module handles this by:
__ai-ready/pages.dumpdb-restore plugin decompresses dump and imports into fresh databasePrerendered pages are always available, even on cold starts.
Use the ai-ready:page:indexed hook to sync with vector databases, search indexes, or analytics:
export default defineNitroPlugin((nitro) => {
nitro.hooks.hook('ai-ready:page:indexed', async (ctx) => {
// Generate embeddings for vector search
const embedding = await openai.embeddings.create({
model: 'text-embedding-3-small',
input: ctx.markdown
})
await vectorDb.upsert({
id: ctx.route,
vector: embedding.data[0].embedding,
metadata: {
title: ctx.title,
description: ctx.description,
route: ctx.route
}
})
console.log(`Indexed ${ctx.route} (update: ${ctx.isUpdate})`)
})
})
Trigger indexing from API routes or plugins:
import { indexPageByRoute } from '#ai-ready'
export default defineEventHandler(async (event) => {
const { paths } = await readBody(event)
const results = await Promise.all(
paths.map((path: string) =>
indexPageByRoute(path, event, { force: true })
)
)
return {
indexed: results.filter(r => r.success && !r.skipped).length,
skipped: results.filter(r => r.skipped).length,
failed: results.filter(r => !r.success).length
}
})
For advanced use cases, access the database directly:
import { searchPages, useDatabase } from '#ai-ready'
export default defineEventHandler(async (event) => {
const { q } = getQuery(event)
// FTS5 full-text search
const results = await searchPages(event, q as string, { limit: 10 })
return results
})
Available query functions:
| Function | Description |
|---|---|
queryPages(event, opts) | Query pages with filters/pagination |
searchPages(event, query, opts) | FTS5 full-text search |
countPages(event, opts) | Count pages matching criteria |
streamPages(event, opts) | Stream pages for large datasets |
upsertPage(event, page) | Insert or update a page |
Combine runtime sync with IndexNow to notify search engines instantly when pages change. When both runtimeSync.cron and indexNow are enabled, IndexNow syncs automatically after each scheduled indexing run.
Use the nuxt-ai-ready CLI to interact with control endpoints:
# Check indexing status
npx nuxt-ai-ready status
# Trigger batch indexing
npx nuxt-ai-ready poll
# Process all pending pages
npx nuxt-ai-ready poll --all
# Preview stale routes (dry run)
npx nuxt-ai-ready prune --dry
# Prune stale routes
npx nuxt-ai-ready prune --ttl 604800
The CLI auto-authenticates using the generated secret. See the CLI guide for all commands and options.