Index of every page on this site: llms.txt

Runtime Sync (Optional)

Enable runtime sync to discover new sitemap routes and control the stored pages used by MCP and other database-backed features. If each deployment prerenders your content, start with that build output.

When You Need Runtime Sync

Enable runtime sync if your site has:

  • Dynamic pages generated at runtime (e.g., user-generated content)
  • Frequently updated content that changes between deploys
  • API-driven pages where content comes from external sources

If content changes only on deploy, prerender the pages during that deployment.

How It Works

  1. Prerendering writes page data and a dump for the deployed server.
  2. The server restores that dump when its database is empty.
  3. Runtime sync seeds routes from the sitemap. Poll requests or cron fetch and index pending pages.

Seeding records routes and their source sitemap lastmod dates. If a valid source date changes, seeding marks the page pending. Poll and cron process pending pages. TTL expiry does not mark an already indexed page pending. If your sitemap omits reliable dates, use the authenticated reindex endpoint or a manual indexing utility after edits.

Enabling Runtime Sync

Runtime sync stores pages in a database. The database needs drizzle-orm, an optional peer dependency. Install it before you turn on runtimeSync or cron:

npx nypm add drizzle-orm@1.0.0-rc.4

If drizzle-orm is missing or older than 1.0.0-rc.4, the build fails and names the install command.

nuxt.config.ts
export default defineNuxtConfig({
  aiReady: {
    runtimeSync: {
      ttl: 3600, // Manual indexing freshness and sitemap refresh interval
      batchSize: 50, // Pages per batch
      pruneTtl: 0 // Prune routes not in sitemap (0 = never)
    },
    cron: true // Optional: scheduled background indexing (every 5 minutes)
  }
})
Set NUXT_APP_SECRET in production to a string with at least 32 characters. AI Ready derives its runtime sync token from this Nuxt secret, also used by OG Image. Nuxt generates a root secret during development. Without a root or legacy token, production requests fail with 500. Invalid application secrets also fail with 500. Run pnpm exec nuxt-ai-ready token to obtain the derived bearer token, including for status requests. The legacy runtimeSyncSecret option and NUXT_AI_READY_RUNTIME_SYNC_SECRET remain supported with a deprecation warning. A non-empty application secret takes precedence over the legacy token.

Control Endpoints

When you enable runtimeSync, these endpoints become available. For example, poll your deployed site with its configured secret:

curl --fail-with-body -X POST 'https://example.com/__ai-ready/poll' \
  -H "Authorization: Bearer $(pnpm exec nuxt-ai-ready token)"

The following request paths and responses are illustrative:

# Check indexing progress (requires the Bearer header)
GET /__ai-ready/status
# Returns: { total: 50, indexed: 45, pending: 5 }

# Trigger batch indexing (requires the Bearer header)
POST /__ai-ready/poll
# Returns: { indexed: 20, remaining: 25, errors: [], duration: 1234, complete: false }

# Process one bounded batch with a timeout check
POST /__ai-ready/poll?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, requires Authorization: Bearer <token> header)
POST /__ai-ready/prune?ttl=604800
# Returns: { pruned: 1, ttl: 604800, dry: false }

# Reindex a single route, e.g. after a CMS publish (requires Authorization: Bearer <token> header)
POST /__ai-ready/reindex?route=/about
# Returns: { route: "/about", indexed: true, contentChanged: true }

# Reindex only when the page is older than the TTL
POST /__ai-ready/reindex?route=/about&force=false
# Returns: { route: "/about", indexed: false, skipped: true }

# A failed fetch or convert answers 502
POST /__ai-ready/reindex?route=/broken
# Returns: { route: "/broken", indexed: false, error: "Failed to fetch HTML for /broken" }

Status and write requests require the configured Bearer token. A prune dry run does not require authentication.

Poll Endpoint Options

Each request processes at most 50 pages, including all=true. If remaining is positive, make another request.

ParamTypeDefaultDescription
limitnumberruntimeSync.batchSize (50)Max pages per batch (max: 50)
allbooleanfalseUse timeout checks within the bounded batch
timeoutnumber30000Max ms for all mode

Prune Endpoint Options

ParamTypeDefaultDescription
drybooleanfalsePreview stale routes without deleting
ttlnumberpruneTtl configPrune routes older than this (seconds)

Reindex Endpoint Options

ParamTypeDefaultDescription
routestring-Route to index. Required. Must start with /
forcebooleantrueIndex even when the page is fresh. Set false to respect the TTL

A route does not need to be in the sitemap or the database seed. Reindex is an authenticated admin action, so it may index any live route. Sitemap discovery supplies the normal pending routes. Poll and cron process pending database rows, including rows restored from build data.

Scheduled Indexing

Cron discovers sitemap routes and processes pending pages, including pages with changed source lastmod dates. Use reindex for an immediate refresh or when your sitemap has no reliable source dates.

When you set cron: true, Nitro scheduled tasks enable automatic background indexing (runs every 5 minutes):

nuxt.config.ts
export default defineNuxtConfig({
  aiReady: {
    cron: true // Runs every 5 minutes, auto-enables runtimeSync
  }
})

The module auto-enables nitro.experimental.tasks when you configure cron.

Cloudflare Workers: The module adds cron triggers to Nitro’s generated Wrangler configuration.

Cloudflare Pages: Keep cron: true to register the production HTTP endpoint. Use an external scheduler to call GET /__ai-ready/cron with Authorization: Bearer <token> header. See the Cloudflare guide for details.

TTL Configuration

OptionDefaultDescription
ttl3600Manual indexing freshness and sitemap refresh interval (seconds)
pruneTtl0Delete routes not in sitemap for this long (0 = never)

Force re-index regardless of TTL:

await indexPage('/about', html, { force: true })

Sitemap Lastmod

Supply a page's source lastmod in your sitemap when a CMS publishes an edit. Runtime sync stores that date separately from indexed content dates. Each sitemap crawl compares valid source dates and queues pages whose dates changed. Equivalent date formats count as one date. Missing or invalid dates do not queue pages.

The module marks dates it adds from the index with an XML comment. Its crawler excludes those marked dates from source comparisons, so enrichment cannot trigger repeated indexing. Keep those comments if another system rewrites your sitemap.

A page's sitemap lastmod comes from a date it declares, such as an article:modified_time meta tag. If a page declares no date, runtime sync dates it from detected content changes:

  • The first index gives the page no date.
  • If a later runtime index finds a different body, the page gets the time of that index.
  • If the body is the same, the stored date stays.

Rows restored from the prerendered dump never count as changed. Their hash comes from the build pipeline, so a difference proves nothing. Without runtime sync, a page with no declared date has no lastmod.

Database Configuration

Runtime sync enables database storage. Every driver needs drizzle-orm. The module selects a driver from the deployment preset and your configuration:

PlatformDriverExtra dependency
Node.jsnode:sqliteNone
Bunbun:sqliteNone
CloudflareD1None
Vercel (with POSTGRES_URL)Neon Postgres@neondatabase/serverless
database.type: 'libsql'LibSQL@libsql/client
database.type: 'postgres'PostgreSQLpostgres

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

For edge deployments, configure D1 or LibSQL:

export default defineNuxtConfig({
  aiReady: {
    database: {
      type: 'd1',
      bindingName: 'DB'
    }
  }
})

Serverless Cold Starts

A local SQLite database may be temporary on a serverless deployment. D1, LibSQL, Neon, and PostgreSQL provide external storage.

Each server process checks the build dump before its first database query. If the database is empty, the module restores __ai-ready/pages.dump from the build output. If the build ID changes, it compares content hashes, adds new pages, and marks changed pages for indexing. Cron runs repeat this check.

The dump must exist and remain accessible to the server. Prerender the pages you need in the initial index.

Sync with External Systems

Use ai-ready:page:indexed after runtime indexing. Check contentChanged before sending Markdown to another service.

server/plugins/indexed-pages.ts
export default defineNitroPlugin((nitro) => {
  nitro.hooks.hook('ai-ready:page:indexed', (ctx) => {
    if (!ctx.contentChanged)
      return

    console.info(`Changed page: ${ctx.route}`)
  })
})

Replace the log with your integration. The database write happens before this hook. If an external request fails, retry that request separately; indexing unchanged content again produces contentChanged: false. See the IndexNow recipe for a complete changed-URL example.

Manual Indexing

For a CMS publish, use the built-in authenticated reindex endpoint:

curl --fail-with-body -X POST 'https://example.com/__ai-ready/reindex?route=/about' \
  -H "Authorization: Bearer $(pnpm exec nuxt-ai-ready token)"

For trusted server code that already has HTML, use indexPage. Do not expose an unauthenticated endpoint that accepts arbitrary URLs to fetch and index.

Direct Database Access

Use the server composables for page queries.

FunctionDescription
queryPages(event, opts)Query pages with filters and pagination
searchPages(event, query, opts)Search stored pages with the configured database
countPages(event, opts)Count pages matching criteria
streamPages(event, opts)Read pages in batches
upsertPage(event, page)Write prepared page data through an explicit #ai-ready/server import

Raw SQL access uses useRawDb from #ai-ready/server. Prefer the query functions unless you need a database-specific operation.

CLI

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

# Use the server batch size, capped at 50 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

# Reindex a single route
npx nuxt-ai-ready reindex /about

The CLI reads the secret cached in your local project. That secret must match the deployed server. See the CLI guide for all commands and options.

Was this page helpful?