Guides
In-depth guides for configuring, writing, and deploying your documentation.
Configuration
mdsvr can be configured via a settings.json file in the _mdsvr/ directory in your docs root. All settings are optional — the server works out of the box with sensible defaults.
Creating settings.json
Use the CLI to create a starter configuration:
npx mdsvr . --init
Or create it manually:
{
"$schema": "https://mdsvr.js.org/schema/v2.json",
"site": {
"title": "My Docs",
"description": "Project documentation"
}
}
Site Settings
{
"site": {
"title": "My Documentation",
"description": "A great documentation site",
"baseUrl": "https://docs.example.com",
"language": "en",
"logo": {
"src": "./assets/logo.svg",
"alt": "My Project",
"href": "/"
},
"favicon": "./assets/favicon.ico"
}
}
Appearance
Control the look and feel of your documentation:
{
"appearance": {
"defaultTheme": "system",
"allowThemeToggle": true,
"accentColor": "#0969da",
"codeTheme": {
"light": "github",
"dark": "github-dark"
}
}
}
Theme Options:
defaultTheme:"light","dark", or"system"(follows OS preference)allowThemeToggle: Show/hide the theme toggle button in the headeraccentColor: Primary color for links, buttons, and accents
Navigation
Configure the sidebar, breadcrumbs, and table of contents:
{
"navigation": {
"sidebar": {
"enabled": true,
"autoGenerate": true,
"collapsible": true,
"defaultOpen": true
},
"breadcrumbs": true,
"prevNextLinks": true,
"tocEnabled": true,
"tocMaxDepth": 3
}
}
Search
Enable and configure the built-in search:
{
"search": {
"enabled": true,
"placeholder": "Search docs...",
"maxResults": 10
}
}
Press ⌘+K (or Ctrl+K) to open the search modal.
SEO
Configure search engine optimization features:
{
"seo": {
"titleTemplate": "%s | My Docs",
"defaultImage": "./assets/og-image.png",
"twitterCard": "summary_large_image",
"twitterSite": "@myhandle",
"generateSitemap": true,
"generateRssFeed": true,
"og": {
"enabled": true,
"imageFormat": "jpg",
"fontFamily": "Inter",
"colors": {
"background": "#0a0a0f",
"text": "#ffffff"
}
},
"rss": {
"title": "My Docs Updates",
"feedUrl": "/feed.xml",
"siteUrl": "https://docs.example.com"
}
}
}
When enabled, these endpoints are automatically generated:
/sitemap.xml— XML sitemap for search engines/feed.xml— RSS feed for blog posts (files withdatein frontmatter)
MDX
Enable MDX support and configure available components:
{
"mdx": {
"enabled": true,
"components": {
"Callout": true,
"CodeGroup": true,
"Steps": true,
"Card": true,
"CardGroup": true,
"Tabs": true,
"Accordion": true,
"Badge": true,
"Mermaid": true
}
}
}
Files
Control which files are served, blocked, or hidden:
{
"files": {
"extensions": {
"serve": [".md", ".mdx", ".png", ".jpg", ".svg", ".css", ".js"],
"block": [".env", ".key", ".pem"],
"hidden": ["settings.json", ".git", "node_modules"]
},
"indexFiles": ["README.md", "index.md", "index.html"],
"ignorePatterns": ["**/node_modules/**", "**/.git/**"],
"staticFolders": ["assets", "public", "images"]
}
}
- Files starting with
_are automatically hidden - Blocked extensions return 403 Forbidden
- Hidden files return 404 Not Found (as if they don’t exist)
staticFolders: Array of folder names to serve as static assets (all files in these folders are served directly)
Footer
Customize the site footer:
{
"footer": {
"text": "Built with mdsvr",
"links": [
{ "label": "GitHub", "href": "https://github.com/..." },
{ "label": "Twitter", "href": "https://twitter.com/..." }
]
}
}
Hot Reload
Settings are automatically reloaded when _mdsvr/settings.json changes (except when using --no-watch flag). You’ll see a message in the console:
[mdsvr] Settings reloaded
Validation
Validate your settings.json:
npx mdsvr . --validate
This will check your configuration and report any errors.
Generate Settings
Configure static export generation options:
{
"generate": {
"basePath": "/docs",
"outputDir": "dist"
}
}
Options:
basePath: Base path for generated URLs (default:""). Useful when deploying to a subdirectory (e.g.,/docs)outputDir: Default output directory for static exports (default:"dist")
These settings are used during static export with the --export flag.
Complete Example
Here’s a complete _mdsvr/settings.json with all available options:
{
"$schema": "https://mdsvr.js.org/schema/v2.json",
"site": {
"title": "My Docs",
"description": "Project documentation",
"baseUrl": "https://docs.example.com",
"language": "en",
"logo": {
"src": "./assets/logo.svg",
"alt": "My Project",
"href": "/"
},
"favicon": "./assets/favicon.ico"
},
"appearance": {
"defaultTheme": "system",
"allowThemeToggle": true,
"accentColor": "#0969da"
},
"navigation": {
"sidebar": {
"enabled": true,
"autoGenerate": true,
"collapsible": true,
"defaultOpen": true
},
"breadcrumbs": true,
"prevNextLinks": true,
"tocEnabled": true,
"tocMaxDepth": 3
},
"search": {
"enabled": true,
"placeholder": "Search docs...",
"maxResults": 10
},
"seo": {
"titleTemplate": "%s | My Docs",
"defaultImage": "./assets/og-default.png",
"twitterCard": "summary_large_image",
"generateSitemap": true,
"generateRssFeed": false,
"og": {
"enabled": true,
"imageFormat": "jpg"
}
},
"files": {
"extensions": {
"serve": [
".md",
".mdx",
".txt",
".pdf",
".png",
".jpg",
".svg",
".css",
".js",
".json"
],
"block": [".env", ".key", ".pem", ".p12"],
"hidden": ["_mdsvr", "settings.json", ".git", "node_modules", ".DS_Store"]
},
"indexFiles": ["README.md", "index.md", "INDEX.md"]
},
"mdx": {
"enabled": true,
"components": {
"Callout": true,
"CodeGroup": true,
"Steps": true,
"Card": true,
"CardGroup": true,
"Tabs": true,
"Accordion": true,
"Badge": true,
"Mermaid": true
}
},
"footer": {
"text": "Built with mdsvr",
"links": [{ "label": "GitHub", "href": "https://github.com/..." }]
}
}
Writing Content
Tips and best practices for creating great documentation.
File Organization
docs/ ├── README.md # Homepage ├── 01-getting-started/ # Getting started guides ├── 02-settings/ # Settings & configuration ├── 03-features/ # Feature documentation └── 04-reference/ # API/reference docs
Frontmatter
Every page should have frontmatter:
---
title: Page Title
description: Brief description for SEO
---
Optional fields:
---
title: Page Title
description: Description
date: 2025-01-15 # For RSS feed
author: John Doe # Attribution
tags: [setup, guide] # For organization
noIndex: true # Exclude from search
---
Markdown Tips
Use Descriptive Headings
<!-- Good -->
## Installing via npm
<!-- Less clear -->
## Installation
Cross-Reference Links
Use relative paths:
See [configuration guide](./README.md)
Code Blocks
Always specify language:
```javascript
const x = 1;
```
MDX Components
Use components for interactive content:
<Callout type="warning">Important information here</Callout> <Steps> ### Step 1 First step content ### Step 2 Second step content </Steps>
See MDX Components for all available components.
Images & Assets
Place assets in docs/assets/:

Note: The assets folder is optional - create it if you need to include images in your documentation.
Best Practices
Follow these guidelines to ensure your documentation passes validation and works correctly in both server mode and static export.
File Naming
- Avoid dots in filenames — Don’t use dots in the middle of filenames (except for the extension)
- ❌
0.1.quickstart.mdorconfig.v2.md - ✅
01-quickstart.mdorconfig-v2.md
- ❌
- Use descriptive names —
quickstart.mdnotpage1.md - Use kebab-case — Separate words with hyphens for clean URLs
- Numbered prefixes — Use
01-,02-for ordering in sidebar
Link Structure
- Use relative paths — Never use absolute paths starting with
/- ❌
[Guide](/docs/guide) - ✅
[Guide](./guide)or[Guide](../guide)
- ❌
- Remove file extensions — Links without
.md/.mdxwork in both modes- ❌
[Setup](./setup) - ✅
[Setup](./setup)
- ❌
- Link to directories, not index files — Use directory paths instead of README/index
- ❌
[Getting Started](./01-getting-started/README) - ✅
[Getting Started](./01-getting-started)
- ❌
- Validate anchors — Ensure
#sectionlinks match actual headings
Heading Structure
- Always include an H1 — Every page must have a top-level heading (
# Title) - Maintain hierarchy — Don’t skip heading levels
- ❌ H1 → H3 (skips H2)
- ✅ H1 → H2 → H3
- Use descriptive headings — Make them searchable and meaningful
Assets & Images
- Use relative paths for assets — Same rules as links
- ❌
 - ✅

- ❌
- Ensure files exist — Validator checks for missing images and assets
- Use supported formats — PNG, JPG, SVG, WebP, GIF, ICO
General Guidelines
- Start with a README.md — Required for homepage
- Keep pages focused — One topic per page
- Link liberally — Help users navigate between related topics
- Use MDX components — Callouts for warnings, Steps for procedures
- Add frontmatter — Include title and description for SEO
- Test with validator — Run
npx mdsvr . --validateto check your docs
Validation
Run the validator to check your documentation:
npx mdsvr ./docs --validate
The validator checks for:
- 🔗 Broken internal links
- ⚠️ Absolute paths (should use relative)
- ⚠️ Links with .md/.mdx extensions
- ⚠️ Links to index files (use directory paths)
- 🔗 Broken anchor links
- 🖼️ Missing assets
- 📁 Filenames with dots in the middle
- 📌 Missing H1 headings
- 📝 Heading hierarchy violations
Use --autofix to automatically fix some issues:
npx mdsvr ./docs --validate --autofix
Deployment
Deploy your documentation to any static hosting platform.
Export Static Site
Generate static HTML files:
npx mdsvr ./docs --export
This creates _html/public/ with your static site.
Custom Output
npx mdsvr ./docs --export ./dist
Export Caching
mdsvr uses intelligent caching to speed up exports:
- File-level caching: Only re-renders pages whose source files changed
- OG image caching: Only regenerates OG images when content changes
- Settings tracking: Detects when
_mdsvr/settings.jsonchanges and forces full re-export
The export state is stored in _mdsvr/export-state.json.
Force Full Export
To bypass cache and force a complete re-export:
# Delete export state only
rm _mdsvr/export-state.json
# Then export
npx mdsvr ./docs --export
Note: Only delete export-state.json, not the entire _mdsvr directory, to preserve your settings.
Firebase Hosting
# Export
npx mdsvr ./docs --export
# Deploy
cd _html
firebase init
firebase deploy
Netlify
Via CLI
npx mdsvr ./docs --export
netlify deploy --dir=_html/public --prod
Via Git
- Push docs to GitHub
- Connect repo to Netlify
- Set build command:
npx mdsvr . --export _html/public - Publish directory:
_html/public
Vercel
# vercel.json
{
"buildCommand": "npx mdsvr . --export _html/public",
"outputDirectory": "_html/public"
}
GitHub Pages
# Export to docs folder
npx mdsvr ./src --export ./docs
# Or use GitHub Actions
GitHub Actions Workflow
# .github/workflows/deploy.yml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npx mdsr . --export
- uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./_html/public
Docker
Using Pre-built Image
docker pull ghcr.io/satoshiman/mdsvr:latest docker run -d \ -p 1800:1800 \ -v /path/to/docs:/app/docs \ ghcr.io/satoshiman/mdsvr:latest
Build Your Own
FROM ghcr.io/satoshiman/mdsvr:latest
COPY ./docs /app/docs
docker build -t my-docs . docker run -d -p 1800:1800 my-docs
VPS / Self-Hosted
Export and serve with any web server:
# Export
npx mdsvr ./docs --export /var/www/docs
# Nginx config
server {
listen 80;
root /var/www/docs;
try_files $uri $uri/ $uri.html =404;
}
Clean URLs
Exported sites use clean URLs:
/guide/setup/instead of/guide/setup.html- Works on all modern static hosts
Related
- Getting Started — If you’re new to mdsvr
- Features — Learn about specific features
- CLI Reference — Command-line documentation