terraform-docs¶
Hand-written input tables rot the moment someone adds a variable and forgets the README. terraform-docs parses your Terraform source — inputs, outputs, providers, modules, resources — and generates documentation in whatever format your project speaks. Run it via pre-commit or CI and documentation stops being optional homework nobody grades.
2026 Update
v0.24.0 is current, MIT licensed. The tooling story is boringly stable — .terraform-docs.yml config, inject mode, recursive mode, a maintained pre-commit hook, and the official terraform-docs/gh-actions action. Which means stale module READMEs are now a choice, not an accident.
Quick Hits¶
# Install via mise
mise use -g terraform-docs@0.24
# Generate straight to stdout
terraform-docs markdown table ./modules/vpc # (1)!
# Inject docs between HTML markers in the README
terraform-docs markdown table \
--output-file README.md \
--output-mode inject ./modules/vpc # (2)!
- Formats: markdown table/document, AsciiDoc, JSON/YAML/XML/TOML, pretty, tfvars hcl
- Inject mode writes between marker comments — everything outside them stays untouched
Inject mode looks for these markers in the target file:
Real talk:
- The config file is
.terraform-docs.yml, searched in module root, then.config/, then cwd, then$HOME/.tfdocs.d/. formatter:is the one REQUIRED key — everything else has sane defaults.- Header content comes from description comments in main.tf via
header-from; write descriptions once per variable and stop duplicating them.
Minimal config — enough for most modules:
# .terraform-docs.yml
formatter: markdown table # required key
output:
file: README.md
mode: inject
sort:
enabled: true
by: name
sections:
hide: []
Enforce it locally with pre-commit:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/terraform-docs/terraform-docs
rev: "v0.24.0"
hooks:
- id: terraform-docs-go
Backstop contributors who skipped hooks — regenerate and push docs on every PR:
# .github/workflows/docs.yml
name: terraform-docs
on:
pull_request:
permissions:
contents: write # git-push needs a token with write access
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5 # pin to a commit SHA in production
- uses: terraform-docs/gh-actions@v1 # pin to a commit SHA in production
with:
working-dir: modules/vpc
output-file: README.md
output-method: inject
git-push: "true"
Why this works:
- Docs regenerate from source, so they cannot drift — reviewers see doc diffs in the same PR that changed the module.
- Inject mode preserves hand-written prose around the markers; automation touches only its own section.
- Pre-commit keeps local clones fresh, and the workflow catches everyone who used
--no-verify.
Tips:
- Document-as-you-go: generated tables beat hand-written input lists that rot within two sprints.
- Write each variable description once in source —
header-frompulls description comments into the generated header. - Use recursive mode for monorepo module trees: one command documents every module underneath.
Gotchas:
- Never hand-edit content between BEGIN_TF_DOCS / END_TF_DOCS markers — the next run clobbers it without asking.
- Broken or removed markers fail silently: inject changes nothing and exits fine. Check the diff.
- Commit the generated docs — docs-as-code means reviewers actually see documentation changes in PRs instead of trusting a wiki.
- The gh-action's
git-push: "true"needs a token with write permissions, otherwise the job exits green having pushed nothing.
Reference¶
Documentation:
Related:
- Terraform
- tflint
Last Updated: 2026-08-22 | Vibe Check: Zero-Effort Docs - Module documentation that maintains itself beats every wiki page that ever quietly rotted.
Tags: iac, documentation, terraform