Software Documentation: What to Write, How to Structure It, and Tools That Help
Software documentation best practices in 2026 — API docs with OpenAPI, architecture decision records, README standards, docs-as-code with Docusaurus, and what d
Software Documentation: What to Write, How to Structure It, and Tools That Help
Software documentation is one of those investments that feels unproductive until the moment it isn't. Then — when a new engineer joins, when a client integration fails, when an incident happens at 2am — the absence of documentation costs far more than writing it would have.
The problem isn't usually that teams don't know they need documentation. It's that they don't know what to write, where to write it, or how to keep it from going stale. This guide addresses all three.
The Documentation Types That Actually Matter
Not all documentation has equal ROI. In priority order:
1. README (Highest ROI)
Every repository needs a README that answers the five questions any new team member asks in the first hour:
# Service Name
One sentence: what this service does.
## Prerequisites
- Node.js 20+
- PostgreSQL 16+
- Redis 7+
🌐 Looking for a Dev Team That Actually Delivers?
Most agencies sell you a project manager and assign juniors. Viprasol is different — senior engineers only, direct Slack access, and a 5.0★ Upwork record across 100+ projects.
- React, Next.js, Node.js, TypeScript — production-grade stack
- Fixed-price contracts — no surprise invoices
- Full source code ownership from day one
- 90-day post-launch support included
Quick Start
git clone https://github.com/org/service-name
cd service-name
cp .env.example .env # Fill in required values
npm install
npm run db:migrate
npm run dev # http://localhost:3000
Environment Variables
| Variable | Required | Description |
|---|---|---|
| DATABASE_URL | Yes | PostgreSQL connection string |
| REDIS_URL | Yes | Redis connection string |
| JWT_SECRET | Yes | ≥32 character secret for JWT signing |
| STRIPE_SECRET_KEY | No | Required only for billing features |
🚀 Senior Engineers. No Junior Handoffs. Ever.
You get the senior developer, not a project manager who relays your requirements to someone you never meet. Every Viprasol project has a senior lead from kickoff to launch.
- MVPs in 4–8 weeks, full platforms in 3–5 months
- Lighthouse 90+ performance scores standard
- Works across US, UK, AU timezones
- Free 30-min architecture review, no commitment
Architecture
Brief overview: what this service does, what it depends on, what depends on it. Link to full architecture doc if it exists.
Development
npm run dev— start with hot reloadnpm run test— run test suitenpm run test:watch— watch modenpm run lint— lint + typechecknpm run db:migrate— run pending migrations
Deployment
See deployment guide or CI/CD pipeline runs on merge to main.
A README that answers these questions eliminates 80% of onboarding questions. Write it on day one, update it when things change.
### 2. API Documentation (OpenAPI)
For any HTTP API, OpenAPI (formerly Swagger) is the standard. Generate it from code — don't maintain it separately.
```typescript
// Using Fastify with @fastify/swagger — auto-generates from route schema
import Fastify from 'fastify';
import swagger from '@fastify/swagger';
import swaggerUi from '@fastify/swagger-ui';
const fastify = Fastify();
await fastify.register(swagger, {
openapi: {
info: {
title: 'My API',
description: 'API documentation',
version: '1.0.0',
},
components: {
securitySchemes: {
bearerAuth: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' },
},
},
security: [{ bearerAuth: [] }],
},
});
await fastify.register(swaggerUi, {
routePrefix: '/docs',
uiConfig: { deepLinking: true },
});
// Route schema auto-populates the OpenAPI spec
fastify.post('/users', {
schema: {
summary: 'Create a user',
description: 'Creates a new user account and sends a welcome email',
tags: ['Users'],
body: {
type: 'object',
required: ['email', 'password'],
properties: {
email: { type: 'string', format: 'email', description: 'User email address' },
password: { type: 'string', minLength: 8, description: 'Password (min 8 chars)' },
displayName: { type: 'string', maxLength: 100 },
},
},
response: {
201: {
description: 'User created successfully',
type: 'object',
properties: {
id: { type: 'string', format: 'uuid' },
email: { type: 'string' },
createdAt: { type: 'string', format: 'date-time' },
},
},
400: { description: 'Validation error', $ref: '#/components/schemas/Error' },
409: { description: 'Email already exists' },
},
},
}, createUserHandler);
The /docs route now serves a live Swagger UI with the complete API reference — always in sync with the actual implementation.
For Python (FastAPI):
from fastapi import FastAPI
from pydantic import BaseModel, EmailStr
app = FastAPI(title="My API", description="API documentation", version="1.0.0")
class CreateUserRequest(BaseModel):
email: EmailStr
password: str
display_name: str | None = None
class UserResponse(BaseModel):
id: str
email: str
created_at: str
@app.post("/users", response_model=UserResponse, status_code=201,
summary="Create a user",
description="Creates a new user account and sends a welcome email")
async def create_user(request: CreateUserRequest) -> UserResponse:
...
# FastAPI auto-generates /docs (Swagger UI) and /redoc
3. Architecture Decision Records (ADRs)
ADRs capture why architectural decisions were made — the most valuable and most neglected documentation type.
Format:
# ADR-0023: Use PostgreSQL for all relational data
**Date:** 2025-11-12
**Status:** Accepted
**Decision makers:** Rahul (Eng Lead), Priya (Backend)
## Context
We're starting a new service that needs a relational database.
MySQL, PostgreSQL, and SQLite were considered.
Decision
Use PostgreSQL as our primary relational database.
Rationale
- JSON support (JSONB) handles semi-structured data without a separate NoSQL DB
- Row-level security simplifies multi-tenant data isolation
- TimescaleDB extension available if we need time-series
- Strong ecosystem: Prisma, Drizzle, Knex, pgvector (for AI embeddings)
- Team has more PostgreSQL experience than MySQL
Consequences
- All engineers must know PostgreSQL basics
- Deployment requires PostgreSQL (not SQLite in dev)
- Connection pooling (PgBouncer or RDS Proxy) required for serverless
Alternatives Rejected
- MySQL: weaker JSON support, fewer extensions
- SQLite: not suitable for multi-process/multi-instance deployments
Store ADRs in `docs/decisions/adr-NNNN-title.md`. Never delete old ADRs — even superseded ones explain why you made choices that otherwise look baffling.
### 4. Runbooks
Runbooks document how to handle operational events — incidents, deployments, on-call procedures.
```markdown
# Runbook: High Database Connection Count
Trigger
Alert fires when db_connections_active > 80 for 5 minutes
Diagnosis
- Check what's holding connections:
SELECT pid, usename, application_name, state, query_start, query FROM pg_stat_activity WHERE state != 'idle' ORDER BY query_start; - Check connection pool metrics in Datadog:
db.pool.activeby service
Resolution
If connection leak: Find the service with highest connection count, restart it — it likely has a connection leak bug.
If traffic spike: Scale the connection pool (increase max_connections
in PgBouncer config) or scale app servers down to reduce connections.
If long-running queries: Kill offending queries:
SELECT pg_terminate_backend(pid)
FROM pg_stat_activity
WHERE state = 'active' AND query_start < NOW() - INTERVAL '5 minutes';
Escalation
If unresolved in 30 minutes, page the on-call engineer and open a P1 incident.
---
Documentation Tools (2026)
| Tool | Best For | Hosting |
|---|---|---|
| Docusaurus | Product docs, developer portals | Self-hosted, Vercel |
| Mintlify | API docs, beautiful out of the box | Cloud |
| GitBook | Internal wikis, team knowledge | Cloud |
| Notion | Internal docs, meeting notes | Cloud |
| Confluence | Enterprise, Jira-integrated | Cloud/self-hosted |
| MkDocs + Material | Technical docs, Python projects | Self-hosted |
| OpenAPI (Swagger/Redoc) | API reference | Embedded in app |
Recommendation: Docusaurus for external developer docs, Notion for internal team knowledge, ADRs in git alongside code.
Docs-as-Code
Documentation lives in the same repository as code, reviewed in the same pull requests, versioned with the same git history.
repository/
├── src/
├── tests/
└── docs/
├── decisions/ ← ADRs
│ ├── adr-0001-use-postgresql.md
│ └── adr-0023-use-fastify.md
├── runbooks/ ← Operational procedures
│ ├── high-database-connections.md
│ └── deployment-rollback.md
├── architecture/ ← System design docs
│ └── overview.md
└── api/ ← Auto-generated from code
Enforce documentation in your PR checklist: "API documentation updated (if API changed)" and "README updated (if setup process changed)."
What Makes Documentation Go Stale (And How to Prevent It)
Problem: Documentation written once, updated never.
Solutions:
- Co-locate with code — docs next to code get updated when code changes
- Generate where possible — OpenAPI from code annotations never drifts
- Review docs in PR — make documentation a PR requirement, not an afterthought
- Date-stamp docs — readers know whether to trust a doc from 2019
- Document the "why," not just the "what" — "what" changes constantly; "why" changes rarely
Developer Portal
For APIs consumed externally (by customers or partners), a developer portal dramatically reduces integration support costs.
Components of a good developer portal:
- Quickstart guide — get a working API call in < 10 minutes
- API reference — complete endpoint documentation (generated from OpenAPI)
- Authentication guide — exactly how to get and use API keys
- Code examples — in the languages your customers actually use
- Changelog — what changed and when
- Status page — current availability and incident history
- Sandbox environment — test without using production credentials
Build cost: $15,000–$40,000 for a custom developer portal; $200–$2,000/month for hosted options (ReadMe, Mintlify).
Working With Viprasol
We write, audit, and build documentation infrastructure for engineering teams — from API reference generation through full developer portals.
→ Documentation consultation →
→ API Development Services →
→ Software Development Services →
See Also
- API Development Company
- Software Development Process
- Technical Debt Management
- Startup CTO Responsibilities
About the Author
Viprasol Tech Team
Custom Software Development Specialists
The Viprasol Tech team specialises in algorithmic trading software, AI agent systems, and SaaS development. With 100+ projects delivered across MT4/MT5 EAs, fintech platforms, and production AI systems, the team brings deep technical experience to every engagement. Based in India, serving clients globally.
Need a Modern Web Application?
From landing pages to complex SaaS platforms — we build it all with Next.js and React.
Free consultation • No commitment • Response within 24 hours
Need a custom web application built?
We build React and Next.js web applications with Lighthouse ≥90 scores, mobile-first design, and full source code ownership. Senior engineers only — from architecture through deployment.