Docs as Code: A Practical Guide for Developers
Your code ships with tests, linting, and version history.
Your code ships with tests, linting, and version history. Your documentation ships in a Google Doc that someone forgot to link.
That is the docs-as-code gap. Docs written as code live in the same Git repository as your application, follow the same review process, and get tested with the same rigor. When a pull request changes an API endpoint, the docs PR updates the matching documentation in the same review cycle.
Here is how to start, in a workflow that does not slow you down.
What docs as code means
Docs as code means your documentation files are Markdown, stored in the same repository as your code, edited via pull requests, and validated by automated checks. Start with three steps: (1) move your docs to Markdown files in /docs, (2) add a docs linter and a preview bot, (3) review doc changes in every PR. ForgeMD fits as the editor, local-first Markdown that syncs to Git, with real-time review for non-engineers.
Why it matters (and why it usually fails)
The good reasons
When your README lives in the same repo as your code, version drift stops. The docs version that ships with your release is the docs version in the repo. No more “the docs say X but the code does Y.”
Pull-request review catches doc bugs like code bugs: wrong command, missing parameter, outdated example. Reviewers flag it before it ships.
Search works. Git-grep finds every reference to a function name across code and docs. No more Ctrl+F in a Notion page that is three tabs deep.
Why most teams give up
Docs as code fails when it becomes “another process.” Engineers hate context-switches. If writing documentation means learning a new editor, running a docs server, and figuring out Markdown linting rules, the docs lose.
The successful teams keep it simple: one Markdown file per doc, one folder per product, preview in the PR comment, lint rules that are opinionated defaults you do not customize.
The three-step start
Step 1: Move docs to the repo as Markdown
Create /docs in your repository. For every guide, API reference, and runbook that exists in Google Docs, Notion, Confluence, or wherever they hide, export as Markdown and commit.
/docs
/api
authentication.md
endpoints.md
/guides
getting-started.md
deployment.md
/runbooks
incident-response.md
database-migration.md
Commit a single .md file with the title matching the repo path convention (docs/api/authentication.md → “API Authentication”). Do not overthink it.
Step 2: Add a linter and preview bot
Add a linter so Markdown doesn’t degrade. markdownlint is the standard, it catches inconsistent list markers, trailing spaces, over-long lines, and empty headings. Runs in CI, fails the PR on violations.
Add a preview bot so reviewers see the rendered doc. VitePress, Docusaurus, or mkdocs with the github-actions[bot] comment gives you a “view preview” link on every PR. No more “I cannot read Markdown formatting in the diff.”
Minimal setup (VitePress):
# vitepress.json
{
"docs": {
"base": "docs/",
"repo": "your-org/your-repo",
"editLink": true
}
}
Step 3: Review doc changes in every PR
This is the cultural shift. The PR description template gets a “Docs impact” checkbox. If the PR changes an API endpoint or a config field, the PR must include the doc update, otherwise it does not merge.
Code owners for /docs overlap with code owners for the modules they document. Reviewers know both the code and the doc.
How ForgeMD fits the docs-as-code workflow
ForgeMD bridges the gap between “real Markdown in Git” and “collaborative editing for non-engineers.”
| Docs-as-code workflow | ForgeMD role |
|---|---|
Markdown files in /docs | Import the folder into ForgeMD’s desktop app, files sync to local disk |
| Git PR review | Non-engineers comment inline on docs in ForgeMD; engineers review in the PR |
| Offline editing | Desktop app (Windows, macOS, Linux) works fully offline |
| Format consistency | Editor enforces Markdown + optional lint rules |
| Export back to repo | Export to Markdown, commit back to /docs |
The workflow:
- Import
/docsinto ForgeMD’s desktop app (folder sync). - Non-engineers edit docs in the collaborative editor.
- An engineer exports the updated files back to Markdown and commits.
- CI runs
markdownlinton the commit.
No one loses their preferred tool. No one has to learn a new one.
Linting rules worth adopting
You do not need to customize these. Copy them.
| Rule | What it catches |
|---|---|
| MD009 | Trailing spaces (breaks some Markdown renderers) |
| MD012 | Multiple blank lines (inconsistent spacing) |
| MD013 | Line length (keep readable in diffs: 80 chars) |
| MD024 | No duplicate headings in the same file |
| MD031 | Fenced code blocks need blank lines around them |
| MD041 | First line must be a heading (not a comment) |
| MD043 | No empty headings |
| MD047 | File ends with a single newline, not two |
markdownlint ships with these as defaults. Turn off the few that fight your style (line length is commonly disabled).
Testing docs (yes, really)
Docs as code can be tested, not just linted:
- Links break silently.
lycheeormarkdown-link-checkin CI fails the PR on dead links. - Configuration examples drift. A test that runs
terraform planagainst your documented config catches it. - API references rot. A test that runs the documented curl command against a staging environment validates examples.
Start with link checking. Add one test per quarter.
Common pitfalls (and how teams avoid them)
The “docs desert” problem
One engineer owns docs. Everyone else forgets until the next release. Fix: rotate the docs owner every quarter. The job is not “write all docs”, it is “triage doc PRs, run the linter, keep /docs tidy.”
The format war
Markdown variant A vs B, frontmatter yes vs no, tables supported vs not. Fix: pick one flavor (GitHub Flavored Markdown) and lint it. No debates in PRs.
The “docs behind the firewall” wall
Engineers write docs, but the docs site needs VPN access. Fix: separate the README-style docs (public, in repo) from the internal runbooks (in a private /docs/internal folder). Public docs get a /docs site; internal docs live in the repo and are searchable via git grep.
Getting started this week (minimal version)
- Create
/docsin your repo. Add one Markdown file with your most-referenced guide. - Add a
markdownlintconfig and a GitHub Action that runs it. - Add a preview bot (VitePress or mkdocs with GitHub Pages).
- In your next 3 PRs that touch user-facing behavior, require a doc update.
That is the full cycle. Everything else is optimization.
FAQ
Do all team members need to write Markdown?
No. ForgeMD’s editor supports WYSIWYG and Markdown as two views of the same document. Content teams use rich text; engineers use Markdown. Both commit to the same repo.
What about diagrams?
Mermaid diagrams live in Markdown code blocks. Commit them; CI renders them. ForgeMD supports Mermaid natively, so reviewers see rendered diagrams in the editor.
Can docs as code coexist with a docs site?
Yes. VitePress, Docusaurus, and mkdocs all read from /docs in your repo and generate a site. The repo is the source of truth; the site is the published view.
What if my product is not open source?
Same workflow. The repo is private. Non-engineers access via ForgeMD’s shared links with per-document permissions.
Does ForgeMD sync to Git automatically?
Not out of the box. ForgeMD stores docs as Markdown on local disk. You export and commit, or wire the REST API into your CI pipeline. The desktop app’s folder sync mirrors your local repo, so changes are always on disk.
What formats can I export?
Markdown (native), plus PDF, HTML, DOCX, LaTeX, Epub, and ODT. Extended formats via Pandoc integration.
Create Markdown Documents Without Compromise
Free 5-day trial · Works fully offline · Cancel anytime