next-md-negotiate

Content negotiation for Next.js

Markdown for agents.
HTML for people.
Same URL.

next-md-negotiate serves text/markdown or text/html based on the Accept header — without splitting your routes.

npm install next-md-negotiate

One request, negotiated response

Same path. Different Accept. Different body.

GET/products/42
Accept: text/htmlBrowser
<!DOCTYPE html>
<html>
  <head>…</head>
  <body>
    <h1>Product 42</h1>
    <span>$42.00</span>
  </body>
</html>
text/html~26 KB
Accept: text/markdownLLM agent
# Product 42

**Price:** $42.00
**Category:** Electronics
**In Stock:** Yes

A premium electronic product with exceptional
build quality and innovative features designed
for the modern developer workflow.
text/markdown
~257× smaller~101 B

Try the header

One Accept header is enough to switch formats.

Terminal
$curl -H "Accept: text/markdown" localhost:3000/products/42
# Product 42

**Price:** $42.00
**Category:** Electronics
**In Stock:** Yes

A premium electronic product with exceptional
build quality and innovative features designed
for the modern developer workflow.

How it works

Configure routes, negotiate on Accept, serve both from one path.

Configure

md.config.ts

Map URL patterns to handlers that return markdown. Params are typed from the pattern.

// md.config.ts
export const mdConfig = [
  createMdVersion(
    '/products/[productId]',
    async ({ productId }) => {
      return `# ${name}`
    }
  )
];

Negotiate

Accept header

Browsers request HTML. Agents that send Accept: text/markdown get markdown instead.

Browser   → Accept: text/html
          → React page

LLM agent → Accept: text/markdown
          → markdown body

Serve

Same URL

No parallel endpoints, no sitemap noise, no duplicate-content risk.

GET /products/42

// Browser
Content-Type: text/html · ~26 KB

// Agent
Content-Type: text/markdown · ~101 B

Built for production Next.js

Small surface area. Clear defaults.

One URL, two formats

No /api/products/42.md endpoints. The canonical path serves both HTML and markdown.

Type-safe route params

Patterns like /products/[productId] infer TypeScript types for your handlers.

SEO-safe by design

Crawlers see HTML only. No duplicate content, no wasted crawl budget.

Discoverable by agents

Optional LlmHint tells AI clients markdown is available via Accept.

App Router & Pages

Same config and patterns for both Next.js routers.

One-command setup

npx next-md-negotiate init detects your project and wires routing.

Live on this site

This documentation uses next-md-negotiate

Request any page with Accept: text/markdown to get the markdown version.

curl -H "Accept: text/markdown" <this-url>