See it as a diagram
Everything below, as a diagram you can edit. Describe yours and see it in seconds.
No account needed · Editable canvas, not a picture
terraform-docs: the module reference writes itself
terraform-docs reads a module's HCL and emits its reference documentation: every input with type, default, and description, every output, providers, and requirements. Its inject mode rewrites only the region between two markers in an existing README, so hand-written context above the markers survives while the generated tables below them stay exact. The descriptions come from the description fields in the HCL itself, which puts the prose in the same file, and the same review, as the variable it describes.
Run it as a CI hook and the reference cannot drift: a merged variable change regenerates the table in the same push. The pre-commit variant catches it even earlier, at commit time on the author's machine.
# .github/workflows/tf-docs.yml
name: terraform-docs
on:
push:
branches: [main]
paths: ["modules/**"]
jobs:
docs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with: { ref: main }
- uses: terraform-docs/gh-actions@v1
with:
working-dir: modules/vpc,modules/ecs,modules/rds
output-file: README.md
output-method: inject # rewrites only between the
git-push: "true" # BEGIN_TF_DOCS / END_TF_DOCS markersThe three-way drift problem
Infrastructure truth lives in three places that drift independently: the docs, the HCL config, and the state file recording what actually exists. Terraform itself only referees the second pair: terraform plan reveals config-versus-state drift, the console change someone made at 2am that the code does not know about. Docs-versus-config drift is what terraform-docs closes for module references. That leaves docs versus state, the subtlest gap: documentation generated faithfully from HCL still lies if the HCL itself has unapplied or drifted resources.
The practical discipline: generated docs describe the config, so keep the config true with drift detection, scheduled plan runs or a tool that alerts on out-of-band changes, and let the docs inherit that truth. Documenting the state directly is chasing a moving target; documenting a config you keep honest is a fixed one.
A README per module, docs next to their source
The convention the Terraform ecosystem settled on is one README.md at each module root, the file the Terraform Registry itself renders as the module's documentation page. It scales because it keeps every doc inside the blast radius of the change that could stale it: a PR touching modules/vpc shows modules/vpc/README.md sitting in the same diff, visibly regenerated or visibly forgotten. A central wiki page describing thirty modules has no such adjacency, which is why it is always wrong about at least five of them.
The generated tables cover the what; the hand-written paragraph above the markers covers the why, this module exists because, this input is dangerous when. That paragraph changes rarely, which is exactly the content hand-writing is good at, the same docs checks in CI principles applying to what remains.
The system view: regenerate the diagram on merge
terraform-docs documents one module at a time; nobody sees the system in an inputs table. The architecture diagram, the VPC, the services, the data stores and the boundaries between them, is the doc that answers "what are we running", and it can follow the same generate-then-regenerate discipline. Datadef's AI import accepts pasted Terraform as the prompt, so the first version of the diagram comes from the HCL itself; the Terraform infrastructure diagram generator is the entry point, and living diagram from Terraform covers the source-specific details.
For the ongoing loop, an AI agent connected to the Datadef MCP server (registry name io.datadef/mcp) reads the changed HCL and updates the diagram, invoked as a CI step on merges touching the infrastructure paths or on request during review; it needs an API key, available on paid plans. To be exact: Datadef does not watch the repository and nothing fires without the wired trigger. Shared public, the diagram embeds by URL in the wiki and the runbooks, and the updated version appears everywhere within minutes of the agent's edit.
The three-way drift caveat
Generation covers references and diagrams, not judgment: why the VPC is carved this way, what the IAM boundary is defending against, which module is deprecated for new services. That prose stays human, and the module-README convention at least keeps it adjacent to the code it explains. The live diagram embed requires a public Datadef project, a real constraint for infrastructure whose shape is confidential; the private-repo fallback is agent-regenerated exports committed alongside the HCL. And the regeneration loop is only as reliable as the CI trigger you wire: a paths filter that misses a module directory is a diagram that silently stops following it.
The layering
FAQ
How do I keep infrastructure documentation up to date?
What does terraform-docs do?
What is the three-way drift problem in infrastructure docs?
Can I generate an architecture diagram from Terraform?
Does the infrastructure diagram update when Terraform changes?