People ask ChatGPT, Claude and Perplexity which tool to use before they ever
visit your site. Those agents fetch pages with a small context budget, and a
landing page full of layout markup is a poor source. /llms.txt
(llmstxt.org) is a short Markdown file at your root
that says what the product is and links the pages worth reading.
The format
In this order:
# Name(the only required part).> One-sentence summary.- Free Markdown with no headings: features, how it works, the FAQ.
## Sectionlists of links:- [Label](https://absolute/url): note.- An
## Optionalsection for links an agent may skip when short on room.
Use absolute URLs. An agent reads the file out of context and cannot resolve
/pricing.
Generate it, do not write it
A hand-written llms.txt drifts from the site within a month. If the landing page already reads its copy from one typed object, build the file from that object with a pure function, and unit test the function:
export function buildLlmsTxt({ base, site, nav, sections }: LlmsInput): string {
const lines = [`# ${site.name}`, "", `> ${site.description}`, ""];
// features, steps and FAQ as plain lists, then ## Pages, ## Legal, ## Optional
return `${lines.join("\n")}\n`;
}
Two details matter:
- Collapse whitespace in every string. A newline in a description followed
by
##would start a heading the spec does not allow there. - Skip section anchors.
/#featuresis the home page again. List real pages: pricing, blog, docs, terms, privacy.
Serve it statically
In the Next.js App Router a folder named llms.txt with a route.ts inside
serves /llms.txt. Route handlers are dynamic by default; this one reads no
request data, so render it once at build time:
// src/app/llms.txt/route.ts
export const dynamic = "force-static";
export function GET(): Response {
return new Response(llmsTxt(), {
headers: { "Content-Type": "text/plain; charset=utf-8" },
});
}
If your auth proxy denies by default (Clerk does), add /llms.txt to its public
routes, or every agent gets a redirect to your sign-in page.
Let integrations add sections
Pricing belongs in the file when you have it. Keep an array of extra sections that integrations append to (a payments module adds its plans and prices, a docs site adds its guides), and render each one after "Pages". The core builder never needs to know which integrations exist.