---
title: "Composables · Nuxt AI Ready · Nuxt SEO"
canonical_url: "https://nuxtseo.com/docs/ai-ready/nitro-api/composables"
last_updated: "2026-08-16T09:50:32.587Z"
meta:
  description: "Server-side composables for accessing page data at runtime."
  "og:description": "Server-side composables for accessing page data at runtime."
  "og:title": "Composables · Nuxt AI Ready · Nuxt SEO"
---

Nuxt SEO on GitHub

Switch to AI ReadySwitch to Nuxt SEOSwitch to RobotsSwitch to SitemapSwitch to OG ImageSwitch to Schema.orgSwitch to Link CheckerSwitch to SEO UtilsSwitch to Site ConfigSwitch to Skew Protection

**Nitro API**

# **Composables**

These composables are auto-imported in Nitro server context (API routes, middleware, plugins).

## `**queryPages**`

**Type:** `**(event?: H3Event, options?: QueryPagesOptions) => Promise<PageEntry[] | PageData[]>**`

Unified page query function with filtering, pagination, and optional markdown content.

server/api/pages.get.ts

```ts
import { queryPages } from '#ai-ready'

export default defineEventHandler(async (event) => {
  // Get all pages
  const pages = await queryPages(event)
  return pages
})
```

**Single page lookup:**

server/api/page.get.ts

```ts
export default defineEventHandler(async (event) => {
  const { path } = getQuery(event)
  const page = await queryPages(event, { route: path as string, includeMarkdown: true })
  return page
})
```

**QueryPagesOptions:**

| **Option** | **Type** | **Description** |
| --- | --- | --- |
| `**route**` | `**string**` | Get single page by route |
| `**includeMarkdown**` | `**boolean**` | Include markdown content |
| `**where.pending**` | `**boolean**` | Filter by indexing status |
| `**where.hasError**` | `**boolean**` | Filter by error status |
| `**where.source**` | `**'prerender' \| 'runtime'**` | Filter by source |
| `**limit**` | `**number**` | Max pages to return |
| `**offset**` | `**number**` | Skip first N pages |

**PageEntry:**

| **Property** | **Type** | **Description** |
| --- | --- | --- |
| `**route**` | `**string**` | Page route (e.g., `**/about**`) |
| `**title**` | `**string**` | Page title |
| `**description**` | `**string**` | Meta description |
| `**headings**` | `**string**` | Pipe-separated headings (e.g., `**h1:Title\|h2:Subtitle**`) |
| `**keywords**` | `**string[]**` | Extracted keywords |
| `**updatedAt**` | `**string**` | ISO timestamp |

**PageData:** Extends PageEntry with `**markdown: string**`.

## `**searchPages**`

**Type:** `**(event: H3Event, query: string, options?: SearchPagesOptions) => Promise<SearchResult[]>**`

Full-text search using SQLite FTS5. Searches title, description, route, headings, keywords, and markdown content.

server/api/search.get.ts

```ts
import { searchPages } from '#ai-ready'

export default defineEventHandler(async (event) => {
  const { q } = getQuery(event)
  return searchPages(event, q as string, { limit: 10 })
})
```

**SearchResult:**

| **Property** | **Type** | **Description** |
| --- | --- | --- |
| `**route**` | `**string**` | Page route |
| `**title**` | `**string**` | Page title |
| `**description**` | `**string**` | Meta description |
| `**score**` | `**number**` | BM25 relevance score |

## `**countPages**`

**Type:** `**(event?: H3Event, options?: CountPagesOptions) => Promise<number>**`

Count pages matching criteria.

server/api/stats.get.ts

```ts
import { countPages } from '#ai-ready'

export default defineEventHandler(async (event) => {
  const total = await countPages(event)
  const pending = await countPages(event, { where: { pending: true } })
  return { total, pending, indexed: total - pending }
})
```

## `**streamPages**`

**Type:** `**(event?: H3Event, options?: StreamPagesOptions) => AsyncGenerator<PageData>**`

Stream pages using cursor-based pagination. Useful for large datasets.

server/api/export.get.ts

```ts
import { streamPages } from '#ai-ready'

export default defineEventHandler(async (event) => {
  const pages = []
  for await (const page of streamPages(event, { batchSize: 50 })) {
    pages.push({ route: page.route, title: page.title })
  }
  return pages
})
```

## `**indexPage**`

**Type:** `**(route: string, html: string, options?: IndexPageOptions) => Promise<IndexPageResult>**`

Manually index a page into the database.

server/api/reindex.post.ts

```ts
import { indexPage } from '#ai-ready'

export default defineEventHandler(async (event) => {
  const { path } = await readBody(event)
  const html = await $fetch(path)
  return indexPage(path, html, { force: true })
})
```

**Options:**

| **Option** | **Type** | **Default** | **Description** |
| --- | --- | --- | --- |
| `**ttl**` | `**number**` | config value | Override TTL check |
| `**force**` | `**boolean**` | `**false**` | Re-index even if fresh |
| `**skipHook**` | `**boolean**` | `**false**` | Skip `**ai-ready:page:indexed**` hook |

**Result:**

| **Property** | **Type** | **Description** |
| --- | --- | --- |
| `**success**` | `**boolean**` | Whether indexing succeeded |
| `**skipped**` | `**boolean**` | `**true**` if page was fresh |
| `**isUpdate**` | `**boolean**` | `**true**` if updating existing entry |
| `**contentChanged**` | `**boolean**` | `**true**` if content hash differs |
| `**data**` | `**object**` | Page data if successful |
| `**error**` | `**string**` | Error message if failed |

## `**indexPageByRoute**`

**Type:** `**(route: string, event?: H3Event, options?: IndexPageOptions) => Promise<IndexPageResult>**`

Fetch HTML and index in one call.

server/plugins/warm-cache.ts

```ts
import { indexPageByRoute } from '#ai-ready'

export default defineNitroPlugin(async () => {
  // Pre-warm important pages on startup
  const routes = ['/', '/docs', '/pricing']
  await Promise.all(routes.map(r => indexPageByRoute(r)))
})
```

## `**useDatabase**`

**Type:** `**(event?: H3Event) => Promise<DatabaseAdapter>**`

Direct database access for advanced queries.

server/api/custom.get.ts

```ts
import { useDatabase } from '#ai-ready'

export default defineEventHandler(async (event) => {
  const db = await useDatabase(event)
  const rows = await db.all('SELECT route, title FROM ai_ready_pages WHERE indexed = 1')
  return rows
})
```

## Data Sources

| **Context** | **Source** |
| --- | --- |
| Development | Empty (warning logged) |
| Prerender | [**~~SQLite~~**](https://sqlite.org) via virtual module |
| Runtime | SQLite via [**~~Drizzle ORM~~**](https://orm.drizzle.team/) |

**Was this page helpful?**

### **Related **

[**Nitro Hooks**](https://nuxtseo.com/docs/ai-ready/nitro-api/nitro-hooks)

[**Configuration**](https://nuxtseo.com/docs/ai-ready/api/config)

[**Configuration** Nuxt configuration reference for Nuxt AI Ready.](https://nuxtseo.com/docs/ai-ready/api/config) [**Nitro Hooks** Nitro runtime hooks for modifying markdown output.](https://nuxtseo.com/docs/ai-ready/nitro-api/nitro-hooks)