CoursesMarkdown Routes with Next.jsSection and sitemap routes for agent-friendly docs
Markdown Routes with Next.js

Section and sitemap routes for agent-friendly docs

Set up a dedicated /sitemap.md route and section listings so AI agents and users can quickly discover your documentation structure, access markdown versions of pages, and benefit from optimized queries and caching for navigation versus full article content.
Log in to mark your progress for each Lesson and Task

Section and Sitemap Routes

Individual articles are useful, but agents often want the full picture.

  • Create a dedicated /sitemap.md route for content discovery
  • Understand the two-tier content strategy
  • Optimize queries for navigation vs full content

When an AI agent first encounters your documentation, it needs to discover what's available. The sitemap is the entry point — a structured list of all sections and articles.

/sitemap.md

This is different from an XML sitemap for SEO. It's a human-readable (and agent-readable) markdown document that shows the content structure.

Create the route directory:

mkdir -p src/app/sitemap.md

Create the Route Handler:

import { client } from '@/sanity/client'
import { SITEMAP_QUERY } from '@/sanity/queries'
import { buildSitemapMarkdown } from '@/lib/markdownSerializers'
/**
* Sitemap route at /sitemap.md
* Provides a markdown-formatted index of all documentation.
*/
export async function GET() {
try {
const sections = await client.fetch(SITEMAP_QUERY)
const markdown = buildSitemapMarkdown(sections)
return new Response(markdown, {
headers: {
'Content-Type': 'text/markdown; charset=utf-8',
'Cache-Control': 'public, max-age=300, stale-while-revalidate=600',
},
})
} catch (error) {
console.error('Sitemap route error:', error)
return new Response('Internal server error', { status: 500 })
}
}

The generated sitemap looks like:

# Keplar Docs Sitemap
## How to Access Content as Markdown
- **Any page**: Add `.md` to the URL or use `Accept: text/markdown` header
- **Section listing**: `/docs/[section].md`
- **This sitemap**: `/sitemap.md`
---
## Getting Started
Get up and running with Keplar in minutes.
- [Quickstart](/docs/getting-started/quickstart) — Create your first API call
- [Installation](/docs/getting-started/installation) — Install the SDK
- [Authentication](/docs/getting-started/authentication) — Set up API keys
## API Reference
Complete API documentation.
- [Endpoints](/docs/api-reference/endpoints) — Available endpoints
- [Error Codes](/docs/api-reference/errors) — Error handling

This gives agents:

  1. Instructions for accessing markdown
  2. Full structure of all sections and articles
  3. Summaries to understand what each article covers

We use different query strategies for different purposes:

Section listings and the sitemap don't include article content — just titles, slugs, and summaries:

// SECTION_QUERY - no content field
{
title,
slug,
description,
"articles": *[...] {
title,
slug,
summary // No content!
}
}

This keeps responses small. A section with 20 articles would be overwhelming if every article included full content.

Article routes include the full content:

// ARTICLE_QUERY - includes content
{
title,
slug,
summary,
content, // Full Portable Text
"section": section-> { ... }
}

This is appropriate for single-article requests where the agent wants the complete content.

The folder is literally named sitemap.md:

src/app/sitemap.md/
└── route.ts

This creates a route at /sitemap.md. The .md is part of the path, not a file extension. Next.js handles this correctly.

If you already have a sitemap.ts for XML sitemaps, they won't conflict. /sitemap.xml and /sitemap.md are different routes.

Section routes use the .md suffix pattern, just like articles:

/docs/getting-started.md → Section listing (markdown)
/docs/getting-started → Section page (HTML)

We created a dedicated Route Handler at /md/[section]/route.ts and configured rewrites to handle .md suffix requests.

Test the sitemap:

curl http://localhost:3000/sitemap.md

Expected output:

# Keplar Docs Sitemap
## How to Access Content as Markdown
- **Any page**: Add `.md` to the URL or use `Accept: text/markdown` header
- **Section listing**: `/docs/[section].md`
- **This sitemap**: `/sitemap.md`
---
## Getting Started
...

Test a section listing with the .md suffix:

curl http://localhost:3000/docs/getting-started.md

Or using the Accept header:

curl -H "Accept: text/markdown" http://localhost:3000/docs/getting-started

Expected output:

# Getting Started
Get up and running with Keplar in minutes.
## Articles
- [Quickstart](/docs/getting-started/quickstart)
Create your first API call in under 5 minutes
- [Installation](/docs/getting-started/installation)
Install the SDK for your platform

Different routes get different cache durations:

  • Sitemap — 5 min cache (structure changes rarely)
  • Section — 5 min cache (article list changes rarely)
  • Article — 1 min cache (content may update frequently)
// Sitemap - longer cache
'Cache-Control': 'public, max-age=300, stale-while-revalidate=600'
// Article - shorter cache
'Cache-Control': 'public, max-age=60, stale-while-revalidate=300'
  • /sitemap.md returns the full sitemap
  • /docs/[section].md returns a section listing (articles only, no content)
  • Accept header also works for sections: Accept: text/markdown
  • Sitemap includes instructions for accessing markdown
  • Cache headers are appropriate for each route type
Mark lesson as complete
You have 1 uncompleted task in this lesson
0 of 1