How HTTP content negotiation works and how next-md-negotiate implements it for Next.js applications.
Content negotiation is a mechanism defined in the HTTP specification that allows a client and server to agree on the best representation of a resource. The client sends an Accept header indicating what content types it can handle, and the server responds with the most appropriate format.
This is not new or experimental — it has been part of HTTP since the beginning. When your browser requests a web page, it sends Accept: text/html. When an API client requests JSON, it sends Accept: application/json.
The Accept header tells the server what content types the client understands. next-md-negotiate looks for these markdown types:
text/markdown — the standard MIME typeapplication/markdown — alternative registrationtext/x-markdown — legacy vendor prefixIf the Accept header contains any of these types and the requested URL matches a configured route, the server returns markdown instead of HTML.
The key difference between browsers and LLM agents is the Accept header they send:
| Client | Accept Header | Gets |
|---|---|---|
| Chrome, Firefox, Safari | text/html | Normal HTML page |
| LLM agent / AI crawler | text/markdown | Markdown document |
| curl (default) | */* | Normal HTML page |
| curl (with header) | text/markdown | Markdown document |
Browsers never send text/markdown in their Accept header, so they always receive the normal HTML page. Your site looks and works identically for human visitors.
next-md-negotiate supports all standard Next.js route patterns:
Here is exactly what happens when a request arrives at your Next.js app with content negotiation configured:
mdConfig/md-api/... handler; otherwise it passes through unchangedContent-Type: text/markdown; charset=utf-8 and status 200mdConfig are checked in order. The first matching route handles the request. If your patterns could overlap, put more specific routes first.All your markdown routes are defined in one place: md.config.ts. This file is used by both the route handler (to match requests and generate markdown) and the routing layer (to generate rewrites or middleware logic). There is no duplication between your page routes and your markdown routes.