
Technical Documentation Guide: README, API Docs, and Changelogs
Tried to contribute to an open source project but gave up because there was no README. That's when I realized the true value of good docs.

Tried to contribute to an open source project but gave up because there was no README. That's when I realized the true value of good docs.
Backend: 'Done.' Frontend: 'How to use?'. Automate this conversation with Swagger.

Stop rendering accidental zeros in your React apps. A deep dive into JavaScript's short-circuit evaluation, the difference between Falsy values, and why the `&&` operator is dangerous for numbers. Learn 3 robust patterns (`!!`, ternary, logical comparison) to write bug-free UI code and prevent critical crashes in React Native.

Editing a modal inside a dashboard requires 5 clicks to see changes? Isolate your UI with Storybook and develop components 10x faster.

Using 'as' to silence errors? It's lying to the compiler. Learn why Type Assertions cause runtime crashes and how to use Type Guards instead.

Last year I found a decent open source library. It had exactly the feature I needed and about 1.5k stars. But when I tried to use it, the README was just 3 lines: "This is awesome library. Clone and use it." That was it.
I had no idea how to install it, what the basic usage was, or what options existed. I had to dig through the code myself. After struggling for 30 minutes, I switched to a different library. That's when I realized: no matter how good the code is, nobody will use it without documentation.
On the flip side, I was recently impressed by Supabase's documentation. Code examples were tabbed so you could choose between JavaScript, Python, and Go. Every function had explanations with real use cases. I integrated it in 5 minutes.
That's what it came down to: writing documentation is as important as writing code. Today I'm documenting what I've learned about technical documentation.
When I first uploaded a project to GitHub, I thought the code was pretty clean. But a month later, I couldn't remember what I'd built. The README just said "My awesome project" so of course I was lost.
That's when it hit me: documentation is for future me too. Others might use it, but first I'm the one who gets confused. The me of 6 months from now is basically a different person.
Thinking of README as an invitation made writing easier. When you invite someone to a party, you don't just say "come over." You tell them when, where, what's happening, what to wear, where to park.
README is the same:
# Project Name
## What is this?
One-line description. Like "A blazing fast markdown parser."
## Why does this exist?
Why you built it. What problem it solves.
## Quick Start
Installation and basic example that works immediately.
## Installation
Detailed setup. Required versions, dependencies.
## Usage
Examples for each major feature. Real-world code.
## API Reference
Functions, classes, methods explained.
## Contributing
How to contribute. Issue reporting, PR guidelines.
## License
MIT, Apache 2.0, etc.
Following this structure made the documentation much more organized. Visitors can quickly find what they need.
I used to think badges were just decoration. But I get it now: badges are like traffic lights for trust.




At a glance, you see the build passes, test coverage is 80%, and it's MIT licensed. Instant credibility.
At first I wrote API docs by hand. Every time I modified a function, I had to update the docs too. Naturally they fell out of sync. Code changed but docs were outdated.
Then I discovered JSDoc:
/**
* Fetches user data
*
* @param userId - Unique user identifier
* @param options - Additional options
* @param options.includeProfile - Whether to include profile info
* @returns Promise containing user object
* @throws {UserNotFoundError} When user is not found
*
* @example
* ```typescript
* const user = await getUser('123', { includeProfile: true });
* console.log(user.name);
* ```
*/
async function getUser(
userId: string,
options?: { includeProfile?: boolean }
): Promise<User> {
// implementation
}
Writing comments right above the code eliminated sync issues. Tools like TypeDoc or API Extractor can auto-generate HTML docs.
For REST APIs, I used the OpenAPI (Swagger) spec:
openapi: 3.0.0
info:
title: User API
version: 1.0.0
paths:
/users/{userId}:
get:
summary: Get user by ID
parameters:
- name: userId
in: path
required: true
schema:
type: string
responses:
'200':
description: User found
'404':
description: User not found
Feed this into Redoc or Scalar and you get beautiful interactive docs. You can even test APIs directly.
Initially I wrote changelogs like "Fixed bugs, added features." You couldn't tell which bugs were fixed or which features were added.
Following the Keep a Changelog format made everything clearer:
# Changelog
## [1.2.0] - 2026-02-20
### Added
- Dark mode support
- User profile image upload
### Changed
- Improved login screen UI
- API response speed improved by 30%
### Deprecated
- `oldFunction()` will be removed in next major version. Use `newFunction()` instead
### Fixed
- Fixed bug where session persisted after logout
- Fixed broken images on mobile
### Security
- Patched XSS vulnerability
Organizing by category (Added, Changed, Fixed) makes changes easy to scan. Users know what changes when they upgrade.
Writing changelogs by hand got tedious. So I adopted Conventional Commits.
Write commit messages following rules and you can auto-generate changelogs:
feat: add dark mode
fix: fix logout bug
docs: add installation instructions to README
chore: update dependencies
Tools like standard-version or semantic-release automatically bump versions and generate changelogs:
npx standard-version
# CHANGELOG.md auto-updates
# package.json version bumps
# git tag created
Now if I just write good commits, documentation creates itself.
On a bigger project, documentation grew. One README wasn't enough. I wanted to separate tutorials, guides, and API reference.
Docusaurus was perfect:
npx create-docusaurus@latest my-docs classic
Just write Markdown files and you get auto-generated sidebar, search, and dark mode. Treat documentation like code: version control with Git, review with PRs, auto-deploy with CI/CD.
For Next.js projects, Nextra is even easier. File structure becomes the sidebar:
docs/
getting-started.mdx
api-reference.mdx
guides/
authentication.mdx
deployment.mdx
Six months later someone asked "why did we use MongoDB instead of PostgreSQL?" I couldn't remember. There was definitely a reason.
That's when I started writing Architecture Decision Records (ADR):
# ADR-001: Choose MongoDB as Database
## Status
Accepted
## Context
Need to store user event logs. Schema expected to change frequently.
## Decision
Use MongoDB.
## Consequences
### Positive
- Schemaless allows flexible adaptation
- Easy horizontal scaling
- JSON format works well with JavaScript
### Negative
- Complex JOIN queries are difficult
- Limited transaction support
Record the context, decision, and consequences. Later you can look back and understand "ah, that's why we did it this way."
Explaining complex architecture with words alone has limits. One picture is worth a thousand words.
I started with draw.io, but updating diagrams every time code changed was painful. Everything changed when I discovered Mermaid:
```mermaid
graph TD
A[User] -->|HTTP Request| B[API Gateway]
B --> C[Auth Service]
B --> D[User Service]
C --> E[(Redis)]
D --> F[(PostgreSQL)]
Write diagrams as code in Markdown. Version controlled with Git, easy to modify. GitHub now supports Mermaid natively.
You can also create sequence diagrams:
```mermaid
sequenceDiagram
User->>+API: Login Request
API->>+Auth: Verify Credentials
Auth->>+DB: Check User
DB-->>-Auth: User Data
Auth-->>-API: JWT Token
API-->>-User: Login Success
Developers don't have time. They don't want to read long explanations. They look at examples first.
So I changed the docs:
Before:After:This library provides very powerful features. First you must create a configuration object, which can have multiple properties...
// Quick Start
import { createClient } from 'awesome-lib';
const client = createClient({
apiKey: 'your-key',
timeout: 5000
});
const data = await client.fetch('/users');
Show the example first. Make it copy-pasteable. Then add detailed explanation.
Make it scannable:
Recently I use AI. Throw code at it and ask "explain this function" and it generates a draft.
GitHub Copilot auto-completes JSDoc comments:
/**
* [Copilot auto-generated]
* Calculates the total price including tax
*
* @param price - Base price before tax
* @param taxRate - Tax rate as decimal (e.g., 0.1 for 10%)
* @returns Total price with tax applied
*/
function calculateTotal(price: number, taxRate: number): number {
return price * (1 + taxRate);
}
Not 100% accurate but good enough as a starting point. I just polish it.
Neglected documentation rots. Code changes but docs stay outdated.
So I manage docs like code:
markdownlint to check doc formatting# .github/workflows/docs.yml
name: Docs Check
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Markdown Lint
run: npx markdownlint '**/*.md'
- name: Check Links
run: npx markdown-link-check '**/*.md'
Add documentation to PR checklist:
## PR Checklist
- [ ] Code changes
- [ ] Tests added/updated
- [ ] Documentation updated (README, API docs, Changelog)
At first, writing documentation felt like wasting time. I thought coding was more productive. But I get it now: documentation isn't a cost, it's an investment.
Good documentation means:
Documentation checklist:
READMEDocumentation is the face of your code. It determines first impressions. Worth the time to make it good.