Serve /llms.txt from any Remix or React Router v7 app. Static asset, resource route, or a loader that builds from your MDX content.
Remix (and React Router v7 in framework mode) treats any route that only exports a loader as a resource route — perfect for non-HTML responses like llms.txt. The handler runs on every Remix adapter without changes: Vercel, Cloudflare Workers, Fly, Node.
Because Remix loaders run server-side on every request, you can read from a CMS, Contentlayer, fumadocs, or your MDX collection at build or runtime. Add a long Cache-Control header and Remix's platform handlers will cache the response at the edge.
Pick whichever fits your stack. For most teams the module or a static file is enough; reach for the dynamic route when you need request-time content.
Drop a file at public/llms.txt. No build step, no server logic.
```md # My Remix App > A short summary of what this app does and who it is for. ## Docs - [Getting Started](https://example.com/docs/getting-started): Quick setup guide - [API Reference](https://example.com/docs/api): Full API docs ```
Generate at request time from a CMS, MDX collection, or database. Handler at app/routes/llms[.]txt.ts.
```ts
import type { LoaderFunctionArgs } from '@remix-run/node'
export async function loader(_args: LoaderFunctionArgs) {
const body = await buildLlmsTxt()
return new Response(body, {
headers: {
'Content-Type': 'text/plain; charset=utf-8',
'Cache-Control': 'public, max-age=0, s-maxage=3600, stale-while-revalidate=86400',
},
})
}
async function buildLlmsTxt() {
// Replace with your MDX collection, Contentlayer, or CMS query
return `# My Remix App\n\n> Short summary.\n\n## Docs\n\n- [Getting Started](https://example.com/docs/getting-started)\n`
}
```Escape the dot in the filename so Remix treats /llms.txt as a literal route. Export only a loader — Remix classifies it as a resource route and skips the document shell.
Claude Code, Cursor, and Codex increasingly request markdown via the Accept: text/markdown header. Pairing your llms.txt with per-page markdown responses makes your whole site legible to agents, not just the index.
Generate llms.txt from your URL or browse the llms.txt directory for real examples.
Remix uses dots in route filenames to indicate nested segments. To treat llms.txt as a literal URL, escape the dot with square brackets: app/routes/llms[.]txt.ts. The resulting route serves at /llms.txt.
Yes. React Router v7 in framework mode uses the same resource-route pattern: export a loader, return a Response, and the route serves raw text. The filename convention is identical.
Remix does not have built-in static generation, but you can pre-build llms.txt into public/ via a prebuild script that writes to disk. For adapters that support prerendering (adapter-static forks, Vercel's ISR), cache the loader response for 24h.
A resource route is any Remix route that exports a loader or action without a default component export. Remix skips the HTML document shell and returns your Response directly. Perfect for llms.txt, sitemap.xml, RSS feeds, and OG images.