Docs As Code
Implementing docs-as-code workflows using tools like Docusaurus, MkDocs, and static site generators
You are an expert in docs-as-code practices, using version-controlled Markdown, static site generators, and CI/CD pipelines to manage technical documentation.
## Key Points
- [ ] Docs updated for any user-facing changes
- [ ] New features have a corresponding doc page
- [ ] API reference reflects endpoint changes
- Home: index.md
- Getting Started:
- API Reference: api-reference.md
- admonition
- pymdownx.highlight
- pymdownx.superfences
- pymdownx.tabbed:
- git-revision-date-localized
- name: Lint prose
## Quick Example
```yaml
# Example PR template addition
## Documentation
- [ ] Docs updated for any user-facing changes
- [ ] New features have a corresponding doc page
- [ ] API reference reflects endpoint changes
```
```yaml
# Add to CI
- name: Lint prose
uses: errata-ai/vale-action@v2
with:
files: docs/
```skilldb get technical-writing-skills/Docs As CodeFull skill: 266 linesDocs-as-Code Workflows — Technical Writing
You are an expert in docs-as-code practices, using version-controlled Markdown, static site generators, and CI/CD pipelines to manage technical documentation.
Overview
Docs-as-code treats documentation like source code: it lives in a Git repository, is written in a plain-text format (Markdown, reStructuredText), is reviewed via pull requests, tested in CI, and deployed automatically. This approach eliminates wiki drift, enables collaborative review, and keeps docs in sync with the codebase they describe.
Core Philosophy
Docs-as-code is the principle that documentation should be treated with the same rigor as source code: version-controlled, reviewed in pull requests, tested in CI, and deployed automatically. This approach eliminates the wiki drift that plagues traditional documentation, where pages silently go stale because there is no review process and no one notices until a user hits outdated instructions during a critical moment.
The deepest value of docs-as-code is cultural, not technical. When documentation lives in the same repository as the code and is updated in the same pull request, it becomes part of the definition of done. A feature is not shipped until its documentation is written, reviewed, and merged. This cultural shift -- from documentation as an afterthought to documentation as a first-class deliverable -- is what separates teams with excellent docs from teams with beautiful tooling and empty pages.
Tooling should be chosen for the team that will maintain it, not for the team that will set it up. The most feature-rich documentation platform in the world is worthless if the team does not know how to use it, cannot debug build failures, or avoids contributing because the setup is intimidating. A simple MkDocs site that the entire team understands and actively maintains will always outperform a sophisticated Docusaurus deployment that only one person can operate.
Anti-Patterns
-
Choosing a documentation tool based on features rather than team familiarity. A tool the team does not understand becomes a bottleneck maintained by one person. When that person leaves, the docs infrastructure becomes an unmaintained black box. Choose the simplest tool that meets your needs and that multiple team members can confidently operate.
-
Treating docs-as-code as only a tooling change without establishing review culture. Moving documentation from a wiki to a Git repository achieves nothing if documentation PRs are rubber-stamped or skipped. The review process is the mechanism that keeps documentation accurate and complete. Without it, you get the same stale docs in a different format.
-
Requiring documentation to live in a separate repository from the code it describes. When documentation and code live in different repositories, they are updated in different PRs at different times, and synchronization failures are inevitable. Co-locate documentation with the code whenever possible so both can be reviewed and merged together.
-
Skipping CI validation for documentation builds. A documentation site with broken links, missing pages, or build warnings is a degraded product. Run the documentation build with strict mode in CI on every pull request so these issues are caught before they reach production, not after a user reports them.
-
Setting up elaborate documentation infrastructure before writing any content. Teams sometimes spend weeks configuring plugins, themes, and CI pipelines for a documentation site that has three pages. Start with content. Write the docs that users need most. Add tooling and automation as the volume of content justifies the investment.
Core Principles
1. Documentation Lives with the Code
Store docs in the same repository as the code they describe, or in a dedicated docs repository that mirrors the service structure. This ensures documentation is updated in the same PR as the code change.
my-service/
src/
tests/
docs/
getting-started.md
configuration.md
api-reference.md
adr/
0001-use-rest.md
mkdocs.yml # or docusaurus.config.js
README.md
2. Use a Static Site Generator
Transform Markdown into a searchable, navigable documentation site. Choose a generator that fits your ecosystem:
| Tool | Ecosystem | Strengths |
|---|---|---|
| Docusaurus | React/JS | Versioning, i18n, MDX, plugin ecosystem |
| MkDocs | Python | Simple config, Material theme, fast builds |
| Starlight | Astro | Lightweight, fast, modern component support |
| Sphinx | Python/RST | Cross-references, API doc generation |
| Hugo | Go | Fastest builds, flexible templating |
3. Review Docs in Pull Requests
Documentation changes go through the same review process as code. Reviewers check for accuracy, clarity, completeness, and broken links.
# Example PR template addition
## Documentation
- [ ] Docs updated for any user-facing changes
- [ ] New features have a corresponding doc page
- [ ] API reference reflects endpoint changes
4. Automate Quality Checks in CI
Validate documentation on every pull request to catch issues before they reach production.
# GitHub Actions workflow for docs validation
name: Docs CI
on:
pull_request:
paths:
- 'docs/**'
- 'mkdocs.yml'
jobs:
build-and-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install dependencies
run: pip install mkdocs-material mkdocs-linkcheck
- name: Build docs
run: mkdocs build --strict
# --strict treats warnings as errors (broken links, missing pages)
- name: Check links
run: mkdocs-linkcheck ./site
Implementation Patterns
MkDocs with Material Theme Setup
# mkdocs.yml
site_name: My Service Docs
site_url: https://docs.example.com
repo_url: https://github.com/org/my-service
theme:
name: material
features:
- navigation.tabs
- navigation.sections
- search.suggest
- content.code.copy
nav:
- Home: index.md
- Getting Started:
- Installation: getting-started/install.md
- Quick Start: getting-started/quickstart.md
- Guides:
- Configuration: guides/configuration.md
- Deployment: guides/deployment.md
- API Reference: api-reference.md
- ADRs:
- Overview: adr/index.md
markdown_extensions:
- admonition
- pymdownx.highlight
- pymdownx.superfences
- pymdownx.tabbed:
alternate_style: true
plugins:
- search
- git-revision-date-localized
Docusaurus Setup
// docusaurus.config.js
module.exports = {
title: 'My Service',
url: 'https://docs.example.com',
baseUrl: '/',
onBrokenLinks: 'throw', // Fail the build on broken links
onBrokenMarkdownLinks: 'throw',
presets: [
[
'classic',
{
docs: {
routeBasePath: '/', // Serve docs at site root
sidebarPath: './sidebars.js',
editUrl: 'https://github.com/org/repo/edit/main/',
showLastUpdateTime: true,
showLastUpdateAuthor: true,
},
},
],
],
themeConfig: {
navbar: {
title: 'My Service',
items: [
{ type: 'doc', docId: 'getting-started', position: 'left', label: 'Docs' },
{ href: 'https://github.com/org/repo', label: 'GitHub', position: 'right' },
],
},
},
};
Automated Deployment
# Deploy docs on merge to main
name: Deploy Docs
on:
push:
branches: [main]
paths:
- 'docs/**'
- 'mkdocs.yml'
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Needed for git-revision-date plugin
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- run: pip install mkdocs-material mkdocs-git-revision-date-localized-plugin
- run: mkdocs build
- uses: actions/upload-pages-artifact@v3
with:
path: site/
- uses: actions/deploy-pages@v4
Content Linting with Vale
# .vale.ini
StylesPath = .vale/styles
MinAlertLevel = suggestion
Packages = Google, write-good
[docs/*.md]
BasedOnStyles = Vale, Google, write-good
Google.Passive = warning
Google.We = suggestion
write-good.Weasel = warning
# Add to CI
- name: Lint prose
uses: errata-ai/vale-action@v2
with:
files: docs/
Best Practices
- Set
onBrokenLinks: 'throw'(Docusaurus) or--strict(MkDocs) so broken internal links fail the build and are caught before deployment. - Use the "edit this page" link feature so readers can submit corrections directly, lowering the barrier to community contributions.
- Pin documentation to release versions for libraries and APIs so users on older versions can find the docs that match their installed version.
Common Pitfalls
- Choosing a documentation tool based on features rather than team familiarity — a simple MkDocs setup that the team actually maintains beats a feature-rich Docusaurus site that falls out of date because no one knows React.
- Treating docs-as-code as only a tooling change without establishing a review culture — if documentation PRs are rubber-stamped or skipped, the workflow produces the same stale docs as a wiki, just in a different format.
Install this skill directly: skilldb add technical-writing-skills
Related Skills
API Documentation
Writing clear, complete, and developer-friendly API reference documentation
Architecture Docs
Writing Architecture Decision Records (ADRs) and system design documentation
Changelog Writing
Writing clear changelogs and release notes that communicate changes to different audiences
Code Comments
Writing effective code comments and inline documentation that explain why, not what
Readme Guides
Crafting effective README files and getting-started guides that onboard users quickly
Runbooks
Creating operational runbooks and incident documentation for reliable system operations