Software Architecture Documentation: C4 Model, ADRs, and Living Docs
Software Architecture Documentation That People Actually Read#
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.
108 articles on system design. Browse the full curriculum at codelit.io/blog.
Try it on Codelit
Chaos Mode
Simulate node failures and watch cascading impact across your architecture
Related articles
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 componentsBuild this architecture
Generate an interactive Software Architecture Documentation in seconds.
Try it in Codelit →
Comments