Skip to main content

Phase 71 — TechDocs

TechDocs is Backstage's built-in documentation system. It turns any mkdocs.yml in a repo into a rendered, searchable documentation site that lives inside the Backstage portal — no separate Confluence or Wiki needed.


What Was Deployed

ComponentChange
packages/app/src/App.tsxAdded techdocsPlugin from @backstage/plugin-techdocs/alpha
packages/backend/DockerfileAdded python3-pip + pip3 install mkdocs-techdocs-core==1.4.0
backstage-values.yamlAdded techdocs.builder: 'local' config
minicloud-backstage/mkdocs.ymlTechDocs site for Backstage itself
minicloud-backstage/docs/Overview, Architecture, CI/CD, Plugins pages
go-service skeletonmkdocs.yml + docs/ (index, api, runbook) scaffolded per service
custom-image skeletonmkdocs.yml + docs/ (index, build) scaffolded per image

Architecture — Local Builder

User opens TechDocs page in Backstage


Backstage backend (plugin-techdocs-backend)

├─ Clone repo via GitHub integration

├─ Run mkdocs build (local subprocess in the pod)
│ requires: mkdocs-techdocs-core installed in the container

└─ Serve rendered HTML directly from pod filesystem
(ephemeral — rebuilt on next access if not cached)

Builder mode: local — mkdocs runs as a subprocess inside the Backstage pod. No external CI step, no object storage needed. Simpler than the external builder; suitable for a sub-20-service catalog.

Publisher mode: local — rendered HTML stored in the pod's ephemeral filesystem (/tmp/backstage/techdocs). Lost on pod restart, rebuilt on next access. Acceptable for a homelab-scale platform where regen takes ~2 seconds.

:::info Upgrade path to MinIO When the catalog grows beyond ~50 services, switch to builder: 'external' + publisher.type: 'awsS3' pointing at MinIO (http://10.0.0.1:9000, bucket techdocs). Each repo's CI adds a @techdocs/cli publish step. The MinIO root user is admin; the password is in Vault at secret/platform/minio. :::


Configuration (backstage-values.yaml)

appConfig:
techdocs:
builder: 'local'
generator:
runIn: 'local'
publisher:
type: 'local'

Dockerfile Change

The node:24-trixie-slim base image has Python 3 pre-installed but not pip. Two additions:

# In the first apt-get layer:
apt-get install -y --no-install-recommends python3 python3-pip g++ build-essential

# New layer after apt installs:
RUN pip3 install mkdocs-techdocs-core==1.4.0 --break-system-packages

mkdocs-techdocs-core is a Backstage meta-package that bundles mkdocs-material, the search plugin, and the Backstage TechDocs theme in a single install.


Enabling TechDocs for a Component

Any component can get TechDocs with two additions:

1. catalog-info.yaml annotation:

metadata:
annotations:
backstage.io/techdocs-ref: dir:.

2. mkdocs.yml at the repo root:

site_name: my-service
site_description: One-line description

docs_dir: docs
nav:
- Overview: index.md
- Runbook: runbook.md

plugins:
- techdocs-core

Then create docs/index.md (and any other pages listed in nav:).


What Every New Service Gets

Both scaffold templates (go-service and custom-image) now include a ready-to-go TechDocs setup:

go-service skeleton:

mkdocs.yml
docs/
index.md ← Overview + deployment table + secrets reference
api.md ← GET /healthz + GET /readyz documentation
runbook.md ← kubectl one-liners, Vault secret rotation, rollback steps

custom-image skeleton:

mkdocs.yml
docs/
index.md ← Overview + image registry info
build.md ← CA cert injection, CI pipeline, local build steps

All pages use ${{ values.name }} and ${{ values.description }} substitution — they're pre-filled with real content, not placeholder text.


Gotcha — {% raw %} in mkdocs.yml skeleton

The scaffold template renders mkdocs.yml through Nunjucks. The ${{ values.name }} substitution works because Nunjucks sees ${{ }} as a template expression.

If you ever need literal ${{ }} in a TechDocs page (e.g., to document GHA syntax), use Nunjucks escaping:

{{ '{{' }} becomes {{

Or wrap the whole file in {% raw %}...{% endraw %} in the skeleton if the file has no Nunjucks substitutions.


Gotcha — catalog-info.yaml already present in minicloud-backstage

The minicloud-backstage/catalog-info.yaml already had backstage.io/techdocs-ref: dir:. from Phase 70 catalog hardening. Adding mkdocs.yml and docs/ was all that was needed to activate TechDocs for it.