Developer Documentation Site — Best Practices Guide
For agents or developers building a full doc site targeting a developer audience. Tech approach: use an existing tool (Docusaurus / VitePress / Nextra).
1. Choose Your Tool
| Criteria | Docusaurus | VitePress | Nextra |
|---|---|---|---|
| Framework | React | Vue 3 | React / Next.js |
| Best for | Large OSS projects, many sections | Lightweight, API ref | Already on Next.js |
| Versioning | ✅ Built-in | Manual | Manual |
| i18n | ✅ Built-in | ✅ Built-in | Plugin |
| Build speed | Moderate | Very fast (Vite) | Fast |
| Search | Algolia built-in | Algolia plugin | Flexsearch |
Quick decision:
- Full doc site with versioning → Docusaurus
- Lightweight API reference, speed is priority → VitePress
- Codebase already uses Next.js → Nextra
Bootstrap Docusaurus
npx create-docusaurus@latest my-docs classic --typescript
cd my-docs
npm run start
Bootstrap VitePress
npx vitepress init
npm run docs:dev
2. Content Structure — The Diátaxis Model
Split all content into 4 types. Never mix them on the same page.
┌─────────────────────────────────────────────────────┐
│ LEARNING │
│ │
│ TUTORIAL │ API REFERENCE │
│ Step-by-step guide │ Technical lookup │
│ → "Build first app" │ → Endpoints, types │
│ │ │
│ P R A C T I C A L ── + ──── T H E O R E T I C A L│
│ │ │
│ HOW-TO GUIDE │ EXPLANATION │
│ Solve a specific task │ Concepts & architecture│
│ → "Setup OAuth 2.0" │ → "How auth works" │
│ │
│ WORKING │
└─────────────────────────────────────────────────────┘
Rules for each type
Tutorial
- Always have a clear, visible output after each step ("After this step, you will see...")
- Short sentences, lots of code blocks, no lengthy theory
- Assume the reader knows nothing, but has already set up their environment
- Open with: "In this tutorial, you will build X"
How-to Guide
- Open with: "In this guide, you will learn how to X"
- One guide = one specific goal
- No need to explain why — just what to do
- Can assume the reader already knows the basics
API Reference
- Auto-generate from OpenAPI spec whenever possible (use Redocly or Stoplight)
- Every endpoint needs: one-line description, params, real request/response example, error codes
- Do not explain workflows — only describe behavior
- Always include type definitions for every field
Explanation
- Explains "why" and "how" at a conceptual level
- No instructions, no step-by-step code
- Use when the team keeps getting asked the same architecture question
3. Directory Structure
Docusaurus
my-docs/
├── docs/
│ ├── getting-started/
│ │ ├── introduction.md ← What & Why (not How)
│ │ ├── quickstart.md ← Working output in < 5 minutes
│ │ └── installation.md
│ ├── tutorials/
│ │ └── build-first-app.md
│ ├── guides/ ← How-to
│ │ ├── authentication.md
│ │ ├── pagination.md
│ │ └── error-handling.md
│ ├── concepts/ ← Explanation
│ │ ├── architecture.md
│ │ └── data-model.md
│ └── api/ ← Reference
│ ├── endpoints.md
│ └── errors.md
├── blog/ ← Changelog, release notes
├── src/
│ ├── components/ ← Custom React components
│ └── css/
│ └── custom.css
├── static/
│ └── img/
└── docusaurus.config.ts
VitePress
docs/
├── .vitepress/
│ └── config.ts
├── getting-started.md
├── guide/
│ ├── index.md
│ └── authentication.md
└── api/
└── index.md
4. Writing Content
Core principles
- Devs don't read — they scan. Use headings, code blocks, and bullet points.
- One page = one purpose. Never mix a tutorial with a reference.
- Code examples must run. Test before publishing.
- Use realistic data. Avoid
foo,bar,example.comwhere possible.
Code Blocks
<!-- ✅ CORRECT: language tag + explanatory comment + realistic data -->
```javascript
// Fetch a user by ID
const response = await fetch('https://api.yourapp.com/users/u_123', {
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json'
}
});
const user = await response.json();
// { id: "u_123", name: "Jane Smith", email: "jane@example.com" }
```
<!-- ❌ WRONG: no language tag, no context -->
```
fetch('/users/123')
```
Callouts / Admonitions
Use to highlight important information:
:::note
Supplementary info — safe to skip without breaking anything.
:::
:::tip
A better approach — recommended.
:::
:::warning
Pay attention — incorrect usage may cause errors.
:::
:::danger
Critical — may result in data loss or a security risk.
:::
Supplementary info — safe to skip without breaking anything.
A better approach — recommended.
Pay attention — incorrect usage may cause errors.
Critical — may result in data loss or a security risk.
File naming convention
# Use kebab-case. No underscores, no camelCase.
✅ getting-started.md
✅ api-authentication.md
❌ GettingStarted.md
❌ api_authentication.md
5. Navigation & Information Architecture
Sidebar — Docusaurus
// docusaurus.config.ts
const sidebars = {
docs: [
{
type: 'category',
label: 'Getting Started',
collapsed: false, // Keep first section open by default
items: [
'getting-started/introduction',
'getting-started/quickstart',
'getting-started/installation',
],
},
{
type: 'category',
label: 'Guides',
items: [
'guides/authentication',
'guides/pagination',
],
},
{
type: 'category',
label: 'API Reference',
items: [{ type: 'autogenerated', dirName: 'api' }],
},
],
};
Navigation rules
- No more than 3 levels deep in the sidebar
- First section is always Getting Started, never collapsed
- API Reference goes at the bottom of the sidebar
- Put the most important page first within each section
6. Search
Use Algolia DocSearch — free for open source, the gold standard for dev docs.
# Apply at: https://docsearch.algolia.com/apply/
# Once approved, add to your config:
// docusaurus.config.ts
themeConfig: {
algolia: {
appId: 'YOUR_APP_ID',
apiKey: 'YOUR_SEARCH_API_KEY', // Search-only key (safe to expose publicly)
indexName: 'YOUR_INDEX_NAME',
contextualSearch: true, // Filters results by current version
},
}
No Algolia yet? Use @easyops-cn/docusaurus-search-local for offline/local search.
7. Versioning
Use Docusaurus's built-in versioning. Do not manage this manually.
# Create a new version (snapshot of the current docs/ folder)
npm run docusaurus docs:version 2.0.0
# Resulting structure:
# versioned_docs/version-1.0.0/ ← frozen
# docs/ ← "next" (work in progress)
Rules:
- Keep at most 2 old versions in the sidebar
- Always show a banner on old versions: "You are viewing docs for v1.x. View latest."
- Avoid versioning the API reference if possible — use a
Deprecatedbadge instead
8. Developer UX Details
Must-haves
| Feature | How to implement |
|---|---|
| Copy button on code blocks | Built into Docusaurus/VitePress — do not disable |
| Dark mode | Enable as default (defaultMode: 'dark') |
| "Edit this page" link | Point to the GitHub repo |
| Breadcrumb | Enable in config |
| Last updated date | Use git timestamps |
| Search | Algolia DocSearch |
Default dark mode config
// docusaurus.config.ts
themeConfig: {
colorMode: {
defaultMode: 'dark',
disableSwitch: false, // Still let users toggle
respectPrefersColorScheme: true,
},
}
Edit this page
// docusaurus.config.ts
presets: [
['classic', {
docs: {
editUrl: 'https://github.com/your-org/your-repo/tree/main/',
showLastUpdateTime: true,
showLastUpdateAuthor: false,
},
}],
],
9. Auto-generate API Reference
Never write API reference by hand if you have an OpenAPI spec.
# Install the plugin
npm install docusaurus-plugin-openapi-docs docusaurus-theme-openapi-docs
// docusaurus.config.ts
plugins: [
[
'docusaurus-plugin-openapi-docs',
{
id: 'api',
docsPluginId: 'classic',
config: {
petstore: {
specPath: 'openapi/openapi.yaml',
outputDir: 'docs/api',
sidebarOptions: {
groupPathsBy: 'tag',
},
},
},
},
],
],
# Generate docs from spec
npm run docusaurus gen-api-docs all
10. SEO & Meta
---
title: Authentication Guide
description: Learn how to authenticate API requests using Bearer tokens and API keys.
keywords: [authentication, api key, bearer token, oauth]
---
// docusaurus.config.ts
themeConfig: {
metadata: [
{ name: 'og:type', content: 'website' },
],
},
11. Deployment
Vercel (recommended for Docusaurus)
// vercel.json
{
"buildCommand": "npm run build",
"outputDirectory": "build",
"framework": "docusaurus2"
}
GitHub Pages
# .github/workflows/deploy.yml
name: Deploy to GitHub Pages
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Required for git last-updated timestamps
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run build
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build
12. Pre-launch Checklist
Content
- Introduction clearly answers "What", "Why", and "Who is this for"
- Quickstart delivers a working output in under 5 minutes
- Every page belongs to exactly one of the 4 types (Tutorial / How-to / Reference / Explanation)
- All code blocks have a language tag
- Code examples have been tested and run successfully
- No broken links (check with
npx linkinator build --recurse)
Technical
- Search is set up (Algolia or local)
- Dark mode works correctly
- Mobile responsive
- "Edit this page" points to the correct GitHub location
- Sitemap is generated (
/sitemap.xml) - 404 page has a link back to the home page
UX
- Copy button works on all code blocks
- Sidebar is no more than 3 levels deep
- Breadcrumb displays correctly
- Page loads fast (under 3s on a slow 3G connection)
13. Build & Maintenance Workflow
1. Write OpenAPI spec → auto-generate API Reference
↓
2. Write the Quickstart tutorial first
(Attract and retain new users)
↓
3. Write How-to guides based on real support tickets
(Address the most frequently asked questions)
↓
4. Write Explanations when the team keeps asking "why"
↓
5. Review: ask a newcomer to read and follow along
(If they get stuck → fix the doc, not the reader)
↓
6. Deploy → monitor search queries with no results
(Zero-result queries = gaps that need to be filled)