Make your Next.js site legible to AI agents — generate a spec-compliant
llms.txt / llms-full.txt manifest and serve any page as raw markdown.
// app/llms.txt/route.ts
import { generateLlmsText } from "@vllnt/next-llms";
export function GET() {
return new Response(
generateLlmsText({
title: "Acme",
summary: "Acme is a widget API.",
sections: [
{
title: "Docs",
links: [{ title: "Quickstart", url: "/docs/quickstart.md" }],
},
],
}),
{ headers: { "Content-Type": "text/plain; charset=utf-8" } },
);
}Emit the llms.txt index and its llms-full.txt companion, and expose any
page's markdown at /path.md so agents skip HTML parsing. Zero runtime
dependencies — pure Web-standard APIs that run in any Next.js runtime (and
Remix, Hono, Deno, …).
- Spec-compliant
llms.txt—generateLlmsTextemits the llmstxt.org shape: an#title, a>blockquote,## Sectionlink lists, and a droppable## Optionalsection. llms-full.txtcompanion —generateLlmsFullTextinlines every page's full markdown so an agent reads the whole site in one request.- Raw-markdown routes —
createMarkdownRouteserves any page astext/markdown, stripping a trailing.mdand resolving the slug through your own content source. - Zero dependencies — pure TypeScript over Web
Request/Response; nothing added to your bundle. - Runtime-agnostic — the route handler imports nothing from
next; it runs on the Edge, Node, or any Web-standard runtime. - Typed end to end — concrete config types guide correct usage; no
any. - Cache-friendly — sensible
Cache-Controldefaults, overridable per route.
pnpm add @vllnt/next-llmsNo peer dependencies.
// app/[...slug]/route.ts — serve any page as raw markdown
import { createMarkdownRoute } from "@vllnt/next-llms";
export const GET = createMarkdownRoute(async (slug) => {
const doc = await getDoc(slug.join("/")); // your content source
return doc?.markdown ?? null; // null → 404
});/docs/intro.md resolves the slug ["docs", "intro"] and returns the markdown
with Content-Type: text/markdown, or 404 when the resolver returns null.
| Export | Kind | Result |
|---|---|---|
generateLlmsText(config) |
function | string — the llms.txt index |
generateLlmsFullText(config) |
function | string — the llms-full.txt bundle |
createMarkdownRoute(resolver, options?) |
factory | (request: Request) => Promise<Response> |
Full reference: docs/API.md.
- No secrets touched — the package generates text and serves whatever your resolver returns.
- Your resolver is the boundary — validate and authorize the slug before returning content.
- Server-controlled cache headers — defaults are safe and overridable per route.
See docs/API.md.
pnpm test # single run
pnpm test:coverage # enforced 100% on covered filesSee CONTRIBUTING.md.
Built by bntvllnt · bntvllnt.com · X @bntvllnt
Part of the @vllnt open-source fleet — vllnt.com
If this is useful, sponsor the work.
MIT — see LICENSE.