Software Architecture Documentation: C4 Model, ADRs, and Living Docs
Most architecture docs are written once and never updated. They rot in Confluence while the system evolves. Here's how to create documentation that stays useful.
The Documentation Problem#
What usually happens:
- Architect draws diagrams in Lucidchart
- Writes a 40-page doc in Confluence
- Team reads it once during onboarding
- System changes, doc doesn't
- New engineer asks "is this still accurate?" → nobody knows
What should happen: Documentation that's close to the code, easy to update, and automatically validated.
The C4 Model#
Simon Brown's C4 model gives you four zoom levels:
Level 1: System Context#
Who uses the system and what external systems does it interact with?
[User] → [Your System] → [Payment Provider]
→ [Email Service]
→ [Analytics]
Audience: Everyone — business stakeholders, new engineers, PMs.
Level 2: Container#
What are the major deployable units (apps, databases, queues)?
[Web App (React)] → [API Server (Node.js)] → [PostgreSQL]
→ [Redis]
→ [Kafka]
→ [Worker (Python)] → [ML Model]
Audience: Engineers, DevOps, architects.
Level 3: Component#
What are the major components inside each container?
API Server:
├── Auth Controller → Auth Service → User Repository
├── Order Controller → Order Service → Order Repository
└── Payment Controller → Payment Service → Stripe Client
Audience: Engineers working on that container.
Level 4: Code#
Class diagrams, function signatures. Usually auto-generated.
Audience: Engineers debugging specific code.
Rule: Most teams only need Levels 1-3. Level 4 is auto-generated or skipped.
Architecture Decision Records (ADRs)#
Document why decisions were made, not just what was built.
ADR Template#
# ADR-001: Use PostgreSQL over MongoDB
## Status: Accepted
## Context
We need a primary database for user and order data.
Our data is relational (users have orders, orders have items).
Team has strong SQL experience.
## Decision
Use PostgreSQL 16 on AWS RDS.
## Consequences
- Strong consistency and ACID transactions
- Need to manage migrations (using Prisma)
- Limited horizontal scaling (read replicas for now)
- Rejected MongoDB because our data is relational
Where to Store ADRs#
docs/
adr/
001-use-postgresql.md
002-event-driven-over-sync.md
003-kubernetes-over-ecs.md
004-jwt-over-sessions.md
In the repo, not in Confluence. ADRs should be reviewed in PRs just like code.
README-Driven Documentation#
Your README is the most-read document in your project:
# Project Name
## Architecture
[Link to interactive diagram on Codelit.io]
## Quick Start
1. Clone → 2. Install → 3. Run
## Services
- **api/** — REST API (Node.js, port 3000)
- **worker/** — Background jobs (Python)
- **web/** — Frontend (Next.js, port 8080)
## Key Decisions
- [ADR-001: PostgreSQL over MongoDB](docs/adr/001-use-postgresql.md)
- [ADR-002: Event-driven architecture](docs/adr/002-event-driven.md)
## Deployment
- Production: Vercel (frontend) + AWS ECS (API)
- CI/CD: GitHub Actions
Living Documentation#
Diagrams as Code#
Generate diagrams from code so they can't go stale:
# Diagrams (Python library)
from diagrams import Diagram
from diagrams.aws.compute import ECS
from diagrams.aws.database import RDS
with Diagram("Production"):
ECS("API") >> RDS("PostgreSQL")
Tools: Mermaid (in Markdown), Structurizr (C4), Diagrams (Python), Codelit.io (AI-generated)
Auto-Generated API Docs#
- OpenAPI/Swagger — generated from code annotations
- GraphQL introspection — schema IS the documentation
- tRPC — TypeScript types ARE the documentation
Architecture Fitness Functions#
Automated tests that verify architecture rules:
// ArchUnit-style test
test("controllers should not depend on repositories directly", () => {
const violations = findImports("src/controllers/**")
.filter(imp => imp.includes("/repositories/"));
expect(violations).toHaveLength(0);
});
Documentation Checklist#
| Document | Where | Update Frequency |
|---|---|---|
| System context diagram | README | Quarterly |
| Container diagram | README or /docs | Monthly |
| ADRs | /docs/adr/ | Per decision |
| API docs | Auto-generated | Every deploy |
| Runbooks | /docs/runbooks/ | Per incident |
| Onboarding guide | /docs/onboarding.md | Quarterly |
Common Mistakes#
- Too much detail — nobody reads 40-page docs
- Wrong audience — C4 Level 3 for a business stakeholder
- Separate from code — Confluence docs rot; in-repo docs get reviewed
- No "why" — ADRs capture reasoning, not just decisions
- Static diagrams — use interactive/generated diagrams that update
Summary#
- C4 model for layered architecture views (context → container → component)
- ADRs for decision history ("why PostgreSQL?")
- README as the entry point — quick start, services, key decisions
- Diagrams as code or AI-generated so they don't go stale
- Auto-generate API docs from code (OpenAPI, GraphQL schema)
- Keep docs in the repo — reviewed in PRs, versioned with code
Generate interactive architecture diagrams at codelit.io — describe any system, export as Mermaid, share live links, embed in docs.
Explore more system design guides at codelit.io/blog.
Try these templates
Netflix Video Streaming Architecture
Global video streaming platform with adaptive bitrate, CDN distribution, and recommendation engine.
10 componentsSearch Engine Architecture
Web-scale search with crawling, indexing, ranking, and sub-second query serving.
8 componentsGoogle Search Engine Architecture
Web-scale search with crawling, indexing, PageRank, query processing, ads, and knowledge graph.
10 componentsContinue learning
Go deeper on system design
As an Amazon Associate I earn from qualifying purchases. Codelit may receive a commission at no extra cost to you.
Building Microservices
Sam Newman · 2021
600 pages on splitting a monolith: service boundaries, data decomposition, migration order.
Release It!
Michael T. Nygard · 2018
Post-mortems of real outages, then the stability patterns (circuit breaker, bulkhead) that stop them.
4.6 (501)#4 in Client-Server Networking SystemsA Philosophy of Software Design
John Ousterhout · 2021
Short book on module depth and complexity, with before/after code showing why an interface is too wide.
Tidy First?
Kent Beck · 2023
A set of small tidyings plus the economics of when to do them, in under a hundred pages.
4.4 (496)