Skip to main content
Writing & LiteratureTechnical Writing266 lines

Docs As Code

Implementing docs-as-code workflows using tools like Docusaurus, MkDocs, and static site generators

Quick Summary36 lines
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 lines
Paste into your CLAUDE.md or agent config

Docs-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:

ToolEcosystemStrengths
DocusaurusReact/JSVersioning, i18n, MDX, plugin ecosystem
MkDocsPythonSimple config, Material theme, fast builds
StarlightAstroLightweight, fast, modern component support
SphinxPython/RSTCross-references, API doc generation
HugoGoFastest 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

Get CLI access →