The Tools of the Trade
Docs-as-Code is not a single tool — it is a stack of tools working together, each with a specific role:
-
Source format — Markdown (
.md): Plain text files living in the same Git repository as the software they describe. Markdown is human-readable without rendering, which means it diffs cleanly in Pull Requests. Some teams use reStructuredText (.rst) for Python projects or AsciiDoc for more complex publishing needs, but Markdown is the dominant choice. -
Engine — Static Site Generator (SSG): Tools like MkDocs (Python, excellent for technical docs), Docusaurus (React-based, popular in the open-source ecosystem), or Hugo (Go, extremely fast builds) convert raw Markdown into a searchable, navigable website. The SSG is configured via a single YAML file that defines navigation structure, theme, and plugins.
-
Process — Pull Request workflow: To change documentation, you open a Pull Request. Changes are reviewed by peers for accuracy, clarity, and completeness — exactly like code review. This is the single most important structural change from the Wiki model.
-
Deployment — CI/CD pipeline: Every merge to
maintriggers a pipeline that builds the static site and deploys it to a hosting service (GitHub Pages, Netlify, an internal Nginx server, or an S3 bucket behind CloudFront). The docs site is always in sync with the latest merged content.
Why This Works
- Synchronization: If you add a new API parameter in the code, you update the
api.mdfile in the same commit. They are versioned together. Agit checkout v2.3.1gives you both the code and the docs for that exact release. - Developer Experience: Developers write docs in the same editor they use for coding. Many IDEs have Markdown preview built in. No browser tab switching, no login to a separate system.
- Quality gates: You can run automated tests on your documentation — spell check, broken link detection, code snippet validation — before merging. A failing doc test blocks the merge, just like a failing unit test.
A Minimal MkDocs Setup
Here is what a real Docs-as-Code repository structure looks like:
my-service/
├── src/ # Application code
├── tests/ # Unit and integration tests
├── docs/ # Documentation source
│ ├── index.md # Home page
│ ├── api-reference.md # API docs
│ ├── architecture.md # System design
│ └── runbooks/
│ └── on-call.md # Operational runbooks
└── mkdocs.yml # SSG configuration
The mkdocs.yml file defines the site:
site_name: My Service Documentation
nav:
- Home: index.md
- API Reference: api-reference.md
- Architecture: architecture.md
- Runbooks:
- On-Call Guide: runbooks/on-call.md
theme:
name: material # The Material for MkDocs theme
plugins:
- search
- git-revision-date-localized # Shows "Last updated: 3 days ago"
Interviewers often ask: "How do you keep documentation up to date?" The weak answer is "we have a culture of documentation." The strong answer describes a system: "We use Docs-as-Code — docs live in the same repo as code, doc changes are required in the same PR as code changes, and our CI pipeline runs broken link checks and code snippet tests on every build. Stale docs fail the build, not just the author's conscience."