---
title: How to add an llms.txt file to a Next.js site
description: Step-by-step guide for both static (public/llms.txt) and dynamic (route handler) approaches in Next.js 13+. Includes verification and validation against the llmstxt.org spec.
last_updated: 2026-05-11
canonical_url: https://agent-ready.dev/how-to-add-llms-txt-to-nextjs
---

# How to add an llms.txt file to a Next.js site

> A step-by-step guide for both static (`public/llms.txt`) and dynamic (route handler) approaches in Next.js 13+.

## What is llms.txt?

llms.txt is a Markdown file served at `/llms.txt` that gives AI systems a curated, plain-text map of a website's most important content. The format was [proposed in late 2024 by Jeremy Howard at Answer.AI](https://llmstxt.org). For the full validation spec, see [our llms.txt checker](https://agent-ready.dev/llms-txt-checker).

## Where should llms.txt live in a Next.js app?

Two valid locations, depending on whether your content is static or generated. For most sites, the static path is correct: drop a file at `public/llms.txt` and Next.js [serves it at the site root](https://nextjs.org/docs/app/api-reference/file-conventions/public-folder) with the correct `text/plain` Content-Type. For sites where the page list is generated — from a CMS, a database, or a build-time index — use a [route handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) at `src/app/llms.txt/route.ts`.

## Step-by-step

### Step 1 — Create the public/llms.txt file

Add a new file at public/llms.txt in your Next.js project. Files placed under public/ are served from the site root automatically — visiting /llms.txt will return the file as-is. No build configuration or route handler is required.

### Step 2 — Add the required Markdown structure

Open the file and add an H1 with your site name, a blockquote summary one or two sentences long, then ## section headings. This is the minimum structure mandated by the llmstxt.org spec. The H1 and blockquote are required; sections are optional but recommended for any site with more than a few pages.

### Step 3 — List your most authoritative pages

Under each ## section, add bullet-point Markdown links in the format [Title](https://example.com/url): one-sentence description. Curate to your most valuable pages — documentation, API reference, policies, key product pages. Quality over quantity: AI systems prefer a short, high-signal index over an exhaustive sitemap.

### Step 4 — Verify it serves correctly

Deploy or start your dev server, then run curl -I https://yoursite.com/llms.txt. You should see HTTP 200 and a Content-Type header that includes text/plain. Next.js serves files under public/ with text/plain for .txt extensions by default, so no configuration is needed.

### Step 5 — Validate against the llmstxt.org spec

Run your URL through agent-ready.dev/llms-txt-checker to confirm the file passes the 9-check llmstxt.org compliance suite — H1 present, blockquote summary, valid Markdown, proper link format, accessible URLs, correct Content-Type, and the optional llms-full.txt companion.

### Example llms.txt

```markdown
# Acme Cloud Widgets

> Widgets-as-a-service for serverless apps. Deploy in one command.

## Documentation

- [Getting started](https://acme.dev/docs/start): Zero to deployed in 60 seconds
- [API reference](https://acme.dev/docs/api): REST endpoints and authentication
- [SDKs](https://acme.dev/docs/sdks): Official client libraries

## Policies

- [Privacy policy](https://acme.dev/privacy): Data handling and retention
- [Terms of service](https://acme.dev/terms): Usage terms

## Optional

- [Sitemap](https://acme.dev/sitemap.xml)
- [llms-full.txt](https://acme.dev/llms-full.txt): Full content bundle
```

### Verify with curl

```bash
curl -I https://yoursite.com/llms.txt

# Expected response:
# HTTP/2 200
# content-type: text/plain; charset=utf-8
```

## How do I generate llms.txt dynamically?

When your page list comes from a database, CMS, or build-time index, use a Next.js [route handler](https://nextjs.org/docs/app/building-your-application/routing/route-handlers) at `src/app/llms.txt/route.ts`. Return a `Response` with an explicit `Content-Type: text/plain` header and the Markdown body assembled from your data source. File-system routes win when both exist, so delete `public/llms.txt` if you switch to the handler.

```typescript
// src/app/llms.txt/route.ts
import { getPublishedPages } from "@/lib/content";

export async function GET() {
  const pages = await getPublishedPages();

  const body = [
    "# Acme Cloud Widgets",
    "",
    "> Widgets-as-a-service for serverless apps.",
    "",
    "## Documentation",
    ...pages.map((p) => `- [${p.title}](${p.url}): ${p.description}`),
  ].join("\n");

  return new Response(body, {
    headers: {
      "Content-Type": "text/plain; charset=utf-8",
      "Cache-Control": "public, max-age=3600",
    },
  });
}
```

The route handler example targets Next.js 13+ (App Router). The static-file path works on the Pages Router with the same `public/llms.txt` location.

## Common pitfalls when adding llms.txt

- **Pages behind authentication.** Links in llms.txt must resolve without a session. Public docs, policies, and marketing pages only.
- **Wrong Content-Type.** If your CDN or middleware rewrites `.txt` to `text/html`, many validators reject the response.
- **JS-only navigation targets.** AI crawlers fetch URLs without running JavaScript; if a linked page's primary content requires a hydrated app, the link is effectively dead.
- **Missing blockquote.** The `>` summary line directly under the H1 is mandatory; without it, strict validators fail the file.
- **Stale links.** Linked URLs that 404 or redirect off-domain hurt your citation quality. Re-check after every site restructure.

## Frequently asked questions

### Does llms.txt need to live at the site root?

The canonical path is /llms.txt at the root of your domain. Some validators also accept /docs/llms.txt or /.well-known/llms.txt, but the root path is what most AI clients try first. Publish at the root; add alternate paths only if you've already shipped them.

### Can I generate llms.txt dynamically with Next.js?

Yes. Create a route handler at src/app/llms.txt/route.ts that returns a Response with Content-Type: text/plain. Build the Markdown from your CMS, database, or sitemap source. Note: file-system routes (public/llms.txt) win when both exist — delete the static file if you want the route handler to take over.

### Do I need an llms-full.txt file too?

Not required, but it helps for docs-heavy sites. llms-full.txt is the optional companion that concatenates the full text of every page in your llms.txt into a single Markdown file. AI clients fetch it when they want more context than the index alone provides. Same Content-Type and location rules apply.

### Does my llms.txt need a special Content-Type header?

It should be served with Content-Type: text/plain (or text/markdown). Next.js sets text/plain automatically for .txt files under public/. If you generate it dynamically, set the header explicitly in your Response. Avoid text/html — most validators treat that as a misconfiguration.

### How do I keep my llms.txt up to date as my site grows?

For static files, edit and redeploy. For dynamic generation, the route handler regenerates on every request (or on a configurable cache window via Cache-Control). For high-velocity sites, hook the regeneration into your sitemap or content-publish flow so llms.txt stays in sync without manual touch.

---

Read the full guide on the web: <https://agent-ready.dev/how-to-add-llms-txt-to-nextjs>

Validate your llms.txt: <https://agent-ready.dev/llms-txt-checker>

## Sitemap

See the full [sitemap](https://agent-ready.dev/sitemap.md) for all pages on agent-ready.dev.
