By Sebastian Cochinescu · June 21, 2026 · 7 min read

How to add llms.txt, JSON-LD, and AI crawler controls to Nuxt

Nuxt sites need the same machine-readable surface as any other modern website: llms.txt, structured data, markdown mirrors, crawler rules, and validation. The key is hooking into the build at the moment Nuxt has actually written your prerendered HTML to disk, so those artifacts reflect the final output.

Where the Nuxt adapter runs

@agentmarkup/nuxt is a Nuxt module that runs after Nitro finishes prerendering. It hooks Nitro's prerender:done event and processes the emitted .output/public directory: the same final-output-first model the other agentmarkup adapters use.

That means it is strongest on the nuxt generate path and on any route you prerender with routeRules or prerender: true. Those are the routes that produce build-time HTML files for the module to read and augment.

What the Nuxt adapter gives you

  • llms.txt generation from your config, with the homepage discovery link injected automatically
  • Optional llms-full.txt with inlined same-site markdown context when mirrors exist
  • JSON-LD injection into emitted HTML plus validation of existing schema blocks
  • Optional markdown mirrors for thin or noisy prerendered pages that need a cleaner fetch target for agents
  • robots.txt patching for AI crawler directives like GPTBot, ClaudeBot, and Google-Extended
  • Header support for Content-Signal and markdown canonicals through the static _headers output
  • Build-time validation for schema mistakes, crawler conflicts, thin HTML, and markdown drift

Basic setup

Install the module:

pnpm add -D @agentmarkup/nuxt

Then register it and pass the shared config under the agentmarkup key:

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@agentmarkup/nuxt'],
  agentmarkup: {
    site: 'https://example.com',
    name: 'Example Docs',
    description: 'Technical docs and product pages.',
    globalSchemas: [
      { preset: 'webSite', name: 'Example Docs', url: 'https://example.com' },
      { preset: 'organization', name: 'Example Inc.', url: 'https://example.com' },
    ],
    llmsTxt: {
      sections: [
        {
          title: 'Documentation',
          entries: [
            {
              title: 'Getting Started',
              url: '/docs/getting-started',
              description: 'Setup guide and first steps',
            },
          ],
        },
      ],
    },
    llmsFullTxt: {
      enabled: true,
    },
    markdownPages: {
      enabled: true,
    },
    contentSignalHeaders: {
      enabled: true,
    },
    aiCrawlers: {
      GPTBot: 'allow',
      ClaudeBot: 'allow',
      PerplexityBot: 'allow',
      'Google-Extended': 'allow',
      CCBot: 'disallow',
    },
  },
})

The config shape is the same AgentMarkupConfig used by the Vite, Astro, and Next.js adapters. Only the integration point changes: Nuxt reads it from the agentmarkup key.

Where it works best

Run a prerendered build and you get the full output flow written into .output/public:

.output/public/
  llms.txt
  llms-full.txt
  robots.txt
  _headers
  docs/getting-started/index.html
  docs/getting-started.md

Because the module reads the directory Nitro actually wrote, the artifacts reflect your real final HTML rather than an earlier build step.

The one caveat that matters

Fully dynamic SSR routes are the boundary. If a route is rendered on demand by the Nitro server and never emits a build-time HTML file, there is no final file for the module to patch afterward.

That does not make the package useless for Nuxt apps. It just means you should be precise about ownership:

  • Use @agentmarkup/nuxt for prerendered routes, nuxt generate output, generated root artifacts, and header output
  • Use the re-exported @agentmarkup/core helpers inside app code (for example a server route or Nitro handler) for truly dynamic routes that have no build-time HTML file

Should you enable markdown mirrors?

Only when they add signal. If your prerendered HTML is already substantial, keep HTML as the primary fetch target. If the built page is thin, noisy, or heavily shell-like, generated markdown mirrors can give fetch-based agents a cleaner path.

agentmarkup keeps that feature disciplined by generating mirrors from final HTML, keeping them directly fetchable, and adding canonical headers back to the HTML route so search engines keep the page itself as the preferred URL.

The bottom line

If your Nuxt app prerenders its pages, @agentmarkup/nuxt is the natural module. It gives you build-time machine-readable output on the same config surface as the other adapters, without stitching the pieces together by hand.

Start with the module for the routes Nuxt prerenders, keep markdown mirrors optional, and use @agentmarkup/core directly only where fully dynamic SSR makes that necessary.

If you need the underlying pieces in more detail, read the llms.txt guide, the JSON-LD guide, and the AI crawlers guide.