---
title: "llms.txt: make your docs readable by AI models · vuejs.school"
description: "llms.txt is a small Markdown file that gives language models a map of your site. Write one by hand, then generate it in Nuxt with nuxt-llms and Nuxt Content."
canonical_url: "https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models"
meta:
  "og:description": "llms.txt is a small Markdown file that gives language models a map of your site. Write one by hand, then generate it in Nuxt with nuxt-llms and Nuxt Content."
  "og:image": "https://vuejs.school/_og/d/a_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscyDCtyB2dWVqcy5zY2hvb2w%2Cc_OgCard.takumi%2Ctitle_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscw%2Cdescription_~bGxtcy50eHQgaXMgYSBzbWFsbCBNYXJrZG93biBmaWxlIHRoYXQgZ2l2ZXMgbGFuZ3VhZ2UgbW9kZWxzIGEgbWFwIG9mIHlvdXIgc2l0ZS4gV3JpdGUgb25lIGJ5IGhhbmQsIHRoZW4gZ2VuZXJhdGUgaXQgaW4gTnV4dCB3aXRoIG51eHQtbGxtcyBhbmQgTnV4dCBDb250ZW50Lg%2Ceyebrow_~VHV0b3JpYWwgwrcgNiBtaW4gcmVhZA%2Ctint_sand%2Cp_Ii9jb21tdW5pdHkvYmxvZy9sbG1zLXR4dC1tYWtlLXlvdXItZG9jcy1yZWFkYWJsZS1ieS1haS1tb2RlbHMi%2Cs_TPkliR18B1R6Y134.png"
  "og:image:alt": "llms.txt: make your docs readable by AI models · vuejs.school"
  "og:image:height": "600"
  "og:image:type": image/png
  "og:image:width": "1200"
  "og:title": "llms.txt: make your docs readable by AI models · vuejs.school"
  "twitter:image": "https://vuejs.school/_og/d/a_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscyDCtyB2dWVqcy5zY2hvb2w%2Cc_OgCard.takumi%2Ctitle_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscw%2Cdescription_~bGxtcy50eHQgaXMgYSBzbWFsbCBNYXJrZG93biBmaWxlIHRoYXQgZ2l2ZXMgbGFuZ3VhZ2UgbW9kZWxzIGEgbWFwIG9mIHlvdXIgc2l0ZS4gV3JpdGUgb25lIGJ5IGhhbmQsIHRoZW4gZ2VuZXJhdGUgaXQgaW4gTnV4dCB3aXRoIG51eHQtbGxtcyBhbmQgTnV4dCBDb250ZW50Lg%2Ceyebrow_~VHV0b3JpYWwgwrcgNiBtaW4gcmVhZA%2Ctint_sand%2Cp_Ii9jb21tdW5pdHkvYmxvZy9sbG1zLXR4dC1tYWtlLXlvdXItZG9jcy1yZWFkYWJsZS1ieS1haS1tb2RlbHMi%2Cs_TPkliR18B1R6Y134.png"
  "twitter:image:alt": "llms.txt: make your docs readable by AI models · vuejs.school"
---

> Index of every page on this site: [llms.txt](https://vuejs.school/llms.txt)

## What goes in an llms.txt file

The [llms.txt proposal](https://llmstxt.org) was published by Jeremy Howard in September 2024. It asks a site to serve a Markdown file at `/llms.txt`, a fixed address like the ones `robots.txt` and `sitemap.xml` use, with a fixed shape:

- An H1 with the name of the project or site. This is the only required part.
- A blockquote with a short summary.
- Any number of plain paragraphs or lists with background, but no further headings.
- H2 sections, each a list of links. Every item is `- [name](url)`, optionally followed by a colon and a short note about what the page contains.
- An H2 called `Optional`, for links a model can skip when it is short on context.

The links should point at Markdown versions of your pages where you have them, because a page of Markdown is far smaller than the same page as HTML. The proposal suggests serving each one at the page's own URL with `.md` added. A file can also live in a subpath, such as `/docs/llms.txt`.

A second file is not in the proposal but has become common alongside it: `llms-full.txt`, the whole documentation set concatenated into one Markdown document. The first file is a map; the second is the territory. Documentation hosts started producing both, and the Nuxt module below does too.

## A convention, not a standard

Be clear with yourself about what this buys. No model vendor has committed to fetching `llms.txt` before answering a question, there is no standards body behind it, and search ranking does not change because the file exists. What it does is make a cheap, well-defined entry point for anything that fetches your site on purpose: an assistant a user pointed at your URL, an agent with a web tool, a script that builds a local knowledge base, or a human who wants the short version. The cost is a few minutes and one static file, so it is a good trade even if it only ever helps your own tooling.

## Write an llms.txt by hand

Take a small documentation site for a fictional component library called Stepper. In a Vite project the file goes in `public/`, which is copied to the root of the build as it is.

*public/llms.txt*

```
# Stepper

> Stepper is a Vue 3 component library for multi-step forms. It ships one component and two composables.

Stepper works with Vue 3.5 and TypeScript. Each page below is available as Markdown at the same URL with a `.md` extension.

## Docs

- [Getting started](https://stepper.example.com/docs/getting-started.md): install, register the component, build a first form
- [Validation](https://stepper.example.com/docs/validation.md): per-step rules and async checks
- [API reference](https://stepper.example.com/docs/api.md): props, events, slots and the two composables

## Optional

- [Changelog](https://stepper.example.com/changelog.md): every release since 1.0
- [Migrating from 1.x](https://stepper.example.com/docs/migration.md)
```

Read it as a model would. The H1 says what this is. The summary, a Markdown blockquote (a line that starts with `>`), says it in two short sentences. The `Docs` section has three links, each with a note that lets a reader decide whether to fetch it. The `Optional` section holds the pages that are only useful sometimes. In sixteen lines, a model learns what Stepper is, which pages exist and which ones it can skip.

Two habits keep the file useful. Keep the notes to one clause, because they are read before the page is fetched. And list fewer pages than you have: the file is a map for a reader with limited attention, not a sitemap.

## Generate it in Nuxt with nuxt-llms

Writing the file by hand is fine for five pages. For a larger documentation site the links should come from the content, and that is what `nuxt-llms` does. It is a module from NuxtLabs that serves `/llms.txt` from a Nuxt app, and `/llms-full.txt` when you ask for it. The examples use the Nuxt 4 layout, with the app in `app/` and `server/` at the root.

```
npm install nuxt-llms
```

The configuration mirrors the file format: a domain, a title, a description, sections of links, and notes. Only `domain` is required. Without it the module logs a warning and serves nothing.

*nuxt.config.ts*

```
export default defineNuxtConfig({
  modules: ['nuxt-llms'],
  llms: {
    domain: 'https://stepper.example.com',
    title: 'Stepper',
    description: 'A Vue 3 component library for multi-step forms.',
    sections: [
      {
        title: 'Docs',
        description: 'One page per topic.',
        links: [
          { title: 'Getting started', href: 'https://stepper.example.com/docs/getting-started', description: 'Install and build a first form' },
          { title: 'API reference', href: 'https://stepper.example.com/docs/api', description: 'Props, events, slots and composables' },
        ],
      },
    ],
    notes: ['Prefer the 2.x docs. The 1.x pages are kept for migration only.'],
    full: {
      title: 'Stepper: full documentation',
      description: 'Every docs page in one file.',
    },
  },
})
```

Start the dev server and open `/llms.txt`. For the config above, the module returns this file:

*/llms.txt, generated*

```
# Stepper

> A Vue 3 component library for multi-step forms.

## Documentation Sets

- [Stepper: full documentation](https://stepper.example.com/llms-full.txt): Every docs page in one file.

## Docs

One page per topic.

- [Getting started](https://stepper.example.com/docs/getting-started): Install and build a first form
- [API reference](https://stepper.example.com/docs/api): Props, events, slots and composables

## Notes

- Prefer the 2.x docs. The 1.x pages are kept for migration only.
```

The title becomes the H1, the description the blockquote, each section an H2 with its description and link list, and `notes` a final `## Notes` section. The `Documentation Sets` section at the top comes from `full`: setting it turns on a second route, `/llms-full.txt`, and links to it, with `full.title` as the link and `full.description` as its note. On its own the module writes nothing into that second file; it stays empty until the hooks below or Nuxt Content fill it.

## Add your own data with Nitro hooks

The links above are still typed by hand. The module's way of filling them from data is a pair of Nitro hooks. Nitro is Nuxt's server engine, and any server plugin (a file in `server/plugins/` that runs when the server starts) can listen to its hooks.

*server/plugins/llms.ts*

```
export default defineNitroPlugin((nitroApp) => {
  nitroApp.hooks.hook('llms:generate', (event, options) => {
    options.sections.push({
      title: 'Playground',
      links: [{ title: 'Live examples', href: `${options.domain}/play`, description: 'Editable demos of every component' }],
    })
  })

  nitroApp.hooks.hook('llms:generate:full', (event, options, contents) => {
    contents.push('# Playground\n\nThe playground at /play lets you edit every example in the browser.')
  })
})
```

`llms:generate` runs each time `/llms.txt` is rendered and gets a copy of the options, so pushing a section here adds it to the output without touching the config. `llms:generate:full` does the same for `/llms-full.txt` and also gets a `contents` array of Markdown strings; whatever you push is joined into the file. This is where a CMS client or a database query would go.

Both routes are prerendered by default. In development the hooks run on every request; in a build they run once, when the routes are prerendered, so the files show your data as it was at build time. Rebuild when it changes.

## Let Nuxt Content fill the sections

If the documentation is already in Nuxt Content, you do not write the hooks yourself. Nuxt Content has shipped the integration since 3.2: when `nuxt-llms` is installed, Content registers both hooks for you. Add both modules to `modules`, as in the config below.

With no further configuration, Content adds one section per collection of type `page`, titled after the collection, with a link for every Markdown document, using the document's title and description. If you want to choose which documents appear, name the collection in a section and filter it.

*nuxt.config.ts*

```
export default defineNuxtConfig({
  modules: ['@nuxt/content', 'nuxt-llms'],
  llms: {
    domain: 'https://stepper.example.com',
    title: 'Stepper',
    description: 'A Vue 3 component library for multi-step forms.',
    sections: [
      {
        title: 'Guides',
        description: 'Step by step pages.',
        contentCollection: 'docs',
        contentFilters: [
          { field: 'extension', operator: '=', value: 'md' },
          { field: 'path', operator: 'LIKE', value: '/docs/guides/%' },
        ],
      },
    ],
    full: { title: 'Stepper: full documentation', description: 'Every docs page in one file.' },
  },
})
```

`contentCollection` names a collection from `content.config.ts`, and each `contentFilters` entry is a `where` clause with a field, an operator such as `=`, `<>`, `LIKE`, `IN` or `IS NULL`, and a value. Once any section names a collection, the automatic per-collection sections are switched off, so list every section you want.

For the full file, Content takes each document's parsed body, turns it back into Markdown with absolute links, and adds an H1 from the title if the body does not start with one. Unlike the hand-written file, the links Content puts in `llms.txt` point at your pages' normal URLs, not at Markdown copies; a model that wants the Markdown finds it in `llms-full.txt`.

## Check the generated files

Run `npx nuxt dev`, then from a second terminal:

```
curl -s http://localhost:3000/llms.txt
curl -s http://localhost:3000/llms-full.txt | head -40
```

Read the output as a stranger would. Check that:

- The summary says honestly, in a sentence or two, what the project is.
- Every link has a note.
- `llms-full.txt` stays under a few hundred kilobytes and is not pulling in the changelog of every release.

Then run `npx nuxt generate` and confirm both files are in `.output/public/` as plain files.

**Check it stuck**3 questions from the llms.txt: make your site readable by models quiz.

[**Practice now**](https://vuejs.school/learn/ai/llms-txt-make-your-site-readable-by-models?tab=quiz)

**Was this helpful?**

## **Keep reading**

[Tutorial · 7 min read**RAG in a Nuxt app: embeddings, retrieval and a chatbot that knows your docs**](https://vuejs.school/community/blog/rag-in-a-nuxt-app-a-chatbot-that-knows-your-docs) [Tutorial · 6 min read**Tools and structured output with the AI SDK 7**](https://vuejs.school/community/blog/tools-and-structured-output-with-the-ai-sdk-7)

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://vuejs.school/#website","@type":"WebSite","description":"A free AI-instructed school for Vue.js. Short tutorials, runnable code and quizzes that adapt to you.","name":"vuejs.school","url":"https://vuejs.school/","publisher":{"@id":"https://vuejs.school/#identity"}},{"@id":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models#webpage","@type":"WebPage","dateModified":"2026-10-27T19:31:40.253Z","datePublished":"2025-11-20","description":"llms.txt is a small Markdown file that gives language models a map of your site. Write one by hand, then generate it in Nuxt with nuxt-llms and Nuxt Content.","name":"llms.txt: make your docs readable by AI models","url":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models","breadcrumb":{"@id":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models#breadcrumb"},"isPartOf":{"@id":"https://vuejs.school/#website"},"potentialAction":[{"@type":"ReadAction","target":["https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models"]}],"primaryImageOfPage":{"@id":"https://vuejs.school/#logo"}},{"@id":"https://vuejs.school/#identity","@type":"Organization","description":"A free AI-instructed school for Vue.js. Short tutorials, runnable code and quizzes that adapt to you.","name":"vuejs.school","url":"https://vuejs.school","logo":{"@id":"https://vuejs.school/#logo"}},{"@id":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models#article","dateModified":"2026-10-27T19:31:40.253Z","datePublished":"2025-11-20","description":"llms.txt is a small Markdown file that gives language models a map of your site. Write one by hand, then generate it in Nuxt with nuxt-llms and Nuxt Content.","headline":"llms.txt: make your docs readable by AI models","inLanguage":"en","isAccessibleForFree":true,"thumbnailUrl":"https://vuejs.school/_og/d/a_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscyDCtyB2dWVqcy5zY2hvb2w%2Cc_OgCard.takumi%2Ctitle_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscw%2Cdescription_~bGxtcy50eHQgaXMgYSBzbWFsbCBNYXJrZG93biBmaWxlIHRoYXQgZ2l2ZXMgbGFuZ3VhZ2UgbW9kZWxzIGEgbWFwIG9mIHlvdXIgc2l0ZS4gV3JpdGUgb25lIGJ5IGhhbmQsIHRoZW4gZ2VuZXJhdGUgaXQgaW4gTnV4dCB3aXRoIG51eHQtbGxtcyBhbmQgTnV4dCBDb250ZW50Lg%2Ceyebrow_~VHV0b3JpYWwgwrcgNiBtaW4gcmVhZA%2Ctint_sand%2Cp_Ii9jb21tdW5pdHkvYmxvZy9sbG1zLXR4dC1tYWtlLXlvdXItZG9jcy1yZWFkYWJsZS1ieS1haS1tb2RlbHMi%2Cs_TPkliR18B1R6Y134.png","@type":["Article","BlogPosting"],"articleSection":["Tutorial"],"author":{"@id":"https://vuejs.school/#identity"},"image":{"@id":"https://vuejs.school/#/schema/image/1"},"isPartOf":{"@id":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models#webpage"},"mainEntityOfPage":{"@id":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models#webpage"},"publisher":{"@id":"https://vuejs.school/#identity"}},{"@id":"https://vuejs.school/community/blog/llms-txt-make-your-docs-readable-by-ai-models#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"Blog","item":"https://vuejs.school/community/blog","position":1},{"@type":"ListItem","name":"llms.txt: make your docs readable by AI models","position":2}]},{"@id":"https://vuejs.school/#logo","@type":"ImageObject","caption":"vuejs.school","contentUrl":"https://vuejs.school/apple-touch-icon.png","inLanguage":"en","url":"https://vuejs.school/apple-touch-icon.png"},{"@id":"https://vuejs.school/#/schema/image/1","@type":"ImageObject","contentUrl":"https://vuejs.school/_og/d/a_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscyDCtyB2dWVqcy5zY2hvb2w%2Cc_OgCard.takumi%2Ctitle_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscw%2Cdescription_~bGxtcy50eHQgaXMgYSBzbWFsbCBNYXJrZG93biBmaWxlIHRoYXQgZ2l2ZXMgbGFuZ3VhZ2UgbW9kZWxzIGEgbWFwIG9mIHlvdXIgc2l0ZS4gV3JpdGUgb25lIGJ5IGhhbmQsIHRoZW4gZ2VuZXJhdGUgaXQgaW4gTnV4dCB3aXRoIG51eHQtbGxtcyBhbmQgTnV4dCBDb250ZW50Lg%2Ceyebrow_~VHV0b3JpYWwgwrcgNiBtaW4gcmVhZA%2Ctint_sand%2Cp_Ii9jb21tdW5pdHkvYmxvZy9sbG1zLXR4dC1tYWtlLXlvdXItZG9jcy1yZWFkYWJsZS1ieS1haS1tb2RlbHMi%2Cs_TPkliR18B1R6Y134.png","inLanguage":"en","url":"https://vuejs.school/_og/d/a_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscyDCtyB2dWVqcy5zY2hvb2w%2Cc_OgCard.takumi%2Ctitle_~bGxtcy50eHQ6IG1ha2UgeW91ciBkb2NzIHJlYWRhYmxlIGJ5IEFJIG1vZGVscw%2Cdescription_~bGxtcy50eHQgaXMgYSBzbWFsbCBNYXJrZG93biBmaWxlIHRoYXQgZ2l2ZXMgbGFuZ3VhZ2UgbW9kZWxzIGEgbWFwIG9mIHlvdXIgc2l0ZS4gV3JpdGUgb25lIGJ5IGhhbmQsIHRoZW4gZ2VuZXJhdGUgaXQgaW4gTnV4dCB3aXRoIG51eHQtbGxtcyBhbmQgTnV4dCBDb250ZW50Lg%2Ceyebrow_~VHV0b3JpYWwgwrcgNiBtaW4gcmVhZA%2Ctint_sand%2Cp_Ii9jb21tdW5pdHkvYmxvZy9sbG1zLXR4dC1tYWtlLXlvdXItZG9jcy1yZWFkYWJsZS1ieS1haS1tb2RlbHMi%2Cs_TPkliR18B1R6Y134.png"}]}
```