Nuxt 4 Implements the llms.txt standard →

Make your Nuxt site
readable by AI

A Markdown mirror of every page, plus a properly sectioned llms.txt index. Zero config — and it publishes your original Markdown, not a lossy HTML round-trip.

$ npx nuxi module add nuxt-llms-txt

MIT licensed · no runtime dependencies added to your bundle · works with nuxi generate and SSR

What you get

Add one line. Build the site.

No route lists to maintain, no frontmatter to add. The module discovers your pages during prerendering and writes everything itself.

nuxt.config.ts the whole setup
export default defineNuxtConfig({
  modules: ['nuxt-llms-txt'],
})
/about.md

A clean Markdown mirror of /about, with title and description frontmatter.

/about + Accept: text/markdown

The same Markdown by content negotiation, served with Vary: Accept.

/llms.txt

A sectioned index of the whole site, following the llmstxt.org convention.

/llms-full.txtopt in

Every page inlined into one file, for one-shot ingestion by a model.

Every HTML page also advertises its mirror with a <link rel="alternate" type="text/markdown"> tag and a matching Link: response header — so agents find it without guessing.
Source fidelity

It publishes your source, not a round-trip.

If a page came from a Markdown file, that file's Markdown is what gets served — MDC components, fence labels, tables and all. Converting rendered HTML back to Markdown throws every one of those away.

HTML round-trip lossy
Keep your key on the server.

```
npm install @acme/sdk
```

// the alert became a bare paragraph
// the language and file label are gone
nuxt-llms-txt byte for byte
::alert{type="warning"}
Keep your key on the server.
::

```bash [npm]
npm install @acme/sdk
```

// exactly what you wrote in content/
Pages that aren't Markdown-backed fall back to HTML conversion automatically, so a mixed site works either way. Detection is automatic with @nuxt/content.
The index

An organised llms.txt, derived from your routes.

Sections come from your route tree. A top-level segment only becomes its own heading once it has children — so a flat marketing site gets one clean list, and a docs site gets real sections.

  • Descriptions are real. Pulled from useSeoMeta, og:description or frontmatter, falling back to the first substantial paragraph.
  • Chrome is stripped. nav, header, footer, aside and anything marked data-ai-ignore never make it in.
  • Override anything. Declare your own sections, mark routes as Optional, or reshape the corpus in a build hook.
llms.txt
# Acme Inc

> Acme builds tools for building tools.

## Pages

- [Acme Inc](https://acme.test/index.md): Acme builds
  developer tools that get out of your way.
- [Pricing](https://acme.test/pricing.md): Simple,
  transparent pricing for teams of every size.

## Docs

- [Documentation](https://acme.test/docs.md): Guides,
  API reference and recipes.
- [Getting started](https://acme.test/docs/getting-started.md):
  Install the SDK and make your first request.

## Optional

- [Terms of service](https://acme.test/legal/terms.md): The
  legal agreement between you and Acme Inc.
Details

The parts you'd otherwise write yourself.

Static or SSR, both

Files are written during prerendering, so nuxi generate needs no server. A Nitro middleware covers SSR-only routes on demand.

Content negotiation

Markdown is served from the HTML route only when the client explicitly asks. */* deliberately still gets HTML, so ordinary API consumers never break.

Per-locale indexes

With @nuxtjs/i18n, each locale gets its own /{locale}/llms.txt. Prefixes are stripped before sections are derived, so /fr/docs lands under Docs.

AI descriptions, opt in

Pages missing a description can have one written at build time. No key means no calls, results are cached by content hash, and a failure never fails your build.

Build hooks

llms-txt:pages to mutate the corpus, llms-txt:files to add, edit or drop outputs just before they're written.

Usable without Nuxt

The conversion and index machinery ships separately as nuxt-llms-txt/core — framework-free, for scripts, CI checks or another adapter.

Comparison

Why another one of these

There are two existing options in the Nuxt ecosystem, and neither does the whole job.

nuxt-llms-txt nuxt-llms @mdream/nuxt
llms.txt
Per-page .md mirrors
Routes discovered automaticallyhand-written
Publishes your original Markdownn/aHTML round-trip
Sectioned index with real descriptionsmanualflat list
Per-locale llms.txt
Works without @nuxt/content
nuxt.config.ts all optional
llmsTxt: {
  // Inferred from site.url when omitted.
  domain: 'https://example.com',
  title: 'Example',
  description: 'What this site is.',

  // exclude is merged with the built-in defaults.
  include: ['/**'],
  optional: ['/legal/**'],

  // Override the derived sections entirely.
  sections: [
    { title: 'Documentation', match: '/docs/**' },
    { title: 'Blog', match: '/blog/**' },
  ],

  markdownFiles: true,   // write /foo.md
  full: false,           // also emit /llms-full.txt
  negotiate: true,      // honour Accept: text/markdown
  source: true,          // prefer original Markdown
}
Configuration

Everything is optional.

The defaults are chosen so that the common case — a Nuxt site that wants to be legible to models — needs nothing but the module name. Reach for config when you want to change the shape of the index, not to make it work.

  • Fully typed. The module augments NuxtConfig, so every option is autocompleted and checked.
  • Sane exclusions built in. /api/**, /_**, /200 and /404 are excluded by default and stay excluded when you add your own.
  • noindex is respected. Pages you keep out of search stay out of the index and the mirrors too.

Ship it in one line.

Then check /llms.txt.

$ npx nuxi module add nuxt-llms-txt