All articles

How to Write Documentation That Actually Gets Read

Most documentation gathers dust. Here's how engineers at companies like Stripe and Linear write docs that developers actually open, finish, and trust.

D

DocPilot Team

AI documentation research and engineering from Onzira Labs.

6 min read

Most documentation is a write-only database

You've seen it. So has everyone who joined a project at 11pm trying to ship a hotfix. The README is 800 words of corporate backstory. The API reference lists every endpoint but never shows a real request. The setup guide assumes you've already cloned three internal repos. The docs were technically written. They were never meant to be read.

Documentation that gets read looks different. It's shorter than you'd expect, more opinionated than feels safe, and ruthlessly structured around the reader's next action instead of the author's favorite topic. The difference isn't talent. It's a handful of concrete choices you can make on the next doc you touch.

Write for the person reading it at 1am, not the author presenting it

Every doc has an implied reader. The mistake is treating that reader as "anyone who might want to know about this." The better question: what is one specific person trying to accomplish in the next ten minutes, and what is the smallest amount of text that gets them there?

Concretely:

  • Lead with the outcome. "Add SSO to your app in 15 minutes" beats "Authentication Overview."
  • Skip the intro paragraph. If the first sentence doesn't tell the reader whether they're in the right place, cut it.
  • Write the section heading first, then the content under it. If you can't fill the section with something the reader needs to do or decide, the heading is wrong.

This is the same instinct behind good UX writing. The doc isn't a place to display what the system contains. It's the path the reader walks.

Structure for scanning, not reading

Engineers don't read docs. They scan, jump, and bail out as soon as they have what they need. Optimize for that behavior and stop apologizing for it.

The inverted pyramid

Put the answer or working code first. Explain after. The classical journalism structure applies directly: who/what/working example up top, context and edge cases below.

A bad opening:

The history of this feature dates back to 2019, when the platform team first identified authentication complexity as a key source of developer friction...

A good opening:

Run this to authenticate:

curl -H "Authorization: Bearer $TOKEN" https://api.example.com/v1/me

The response contains id, email, and organization_id.

Headings as a table of contents

A reader who lands on your page should be able to read only the H2s and know what the doc covers. If your headings are "Introduction," "Background," and "Conclusion," you've failed. If they're "Install the SDK," "Send your first event," "Handle webhooks," the reader can navigate without committing.

Code blocks that actually run

Every code sample in your docs should:

  1. Use real, current values (no your_api_key_here without showing where to find it)
  2. Be copy-paste runnable, not a snippet of a snippet
  3. Show expected output immediately below

Here's the difference in practice:

# Before: a snippet in search of a context
response = client.create(user="test")
print(response.id)
# After: a runnable, self-contained example
from example import Client

client = Client(api_key="sk_test_...")
user = client.users.create(email="alex@example.com")
print(user.id)
# => usr_3F2kQa

The second version costs you three more lines. It saves every reader ten minutes of guessing.

Make the next step obvious

A doc that ends with a paragraph of caveats and no forward path is a dead end. Every page should answer, implicitly or explicitly: what does the reader do next?

Some patterns that work:

  • End setup guides with a "verify it worked" snippet.
  • End reference docs with a link to the most common task built on that endpoint.
  • End conceptual pages with a worked example, even if it duplicates content elsewhere.

Stripe's API docs do this consistently: every endpoint page closes with a one-paragraph "common use cases" block that points the reader at the actual recipes they probably came for.

Match the reader's mental model, not your codebase

Your code is organized by what made sense to the team that built it. Your docs should be organized by what makes sense to someone who didn't.

A few translations that come up constantly:

Internal modelReader-facing concept
Organization, Workspace, Tenant (synonymous)Pick one. Document the one.
customer_id vs user_id vs account_idExplain what each one means in the product, not what table it lives in
A flag called enable_v2_billing_betaEither ship it as v2 billing or don't. Don't expose the flag.

When the reader's mental model and the doc's model disagree, the reader is right and the doc is wrong.

Conventions that compound

A few practices that look small and add up:

  • Use the imperative mood. "Run the migration" not "You can run the migration."
  • One concept per heading. If a section covers two things, it's two sections.
  • Date volatile information. "As of March 2026" or "This behavior changed in v3.2." Docs without dates become lies in six months.
  • Link liberally, but link the noun. "See the rate limits guide" beats "Click here for more info."
  • Keep examples short, then show real ones. A 5-line example teaches the shape. A 30-line example teaches the integration. You need both, on different pages.

Don't hide the failure modes

The single highest-value thing most docs omit is what goes wrong. Newcomers don't need to know your 200 response in detail; they've read five responses today. They need to know what the 422 means, why the webhook didn't fire, and which error code means "fix your code" versus "wait."

A page that includes a "Common errors" section is almost always better than one that doesn't. Stripe, Twilio, and Cloudflare all do this well. The errors table is one of the most-read sections on any reference page, and one of the most-skipped by the people writing the docs.

Treat docs as a product, not an artifact

The biggest shift is treating documentation as something with users, metrics, and a feedback loop — not a deliverable you check off before launch.

Practical moves:

  • Add a "Was this helpful?" widget and read the responses.
  • Watch session recordings or scroll-depth analytics on your key pages.
  • Search your support channels and Discord for phrases like "how do I" — every one is a doc that's missing or unclear.
  • Set up a webhook so docs update when the code changes. If your docs and your code can drift, they will.

This last point is where most teams lose. The doc was perfect in March. In October the SDK renamed a parameter and the example still shows the old name. Nobody noticed because nobody reads the whole doc top to bottom anymore — they just hit the code block and move on.

A short checklist before you publish

Before you hit save:

  1. Does the first sentence tell the reader whether they're in the right place?
  2. Can someone scan the H2s and learn the shape of the topic?
  3. Is every code block runnable, with expected output shown?
  4. Is the next step obvious from the bottom of the page?
  5. Have you included the failure modes?
  6. Will this still be true in six months, and if not, is that dated?

If you can answer yes to most of those, the doc will get read. If you can't, no amount of better copy or prettier design will save it.

Make the docs write themselves

The honest reason most docs are bad isn't laziness — it's that maintaining them is brutal. The code changes on Tuesday, the docs change on Friday if someone remembers, and by next quarter they're fiction. The teams whose docs stay sharp are the ones who automated the link between code and documentation.

If you're spending more time syncing READMEs and architecture docs with your codebase than you spend writing the actual features, DocPilot is built for that problem. It connects to your GitHub repos, reads the code, and generates setup, README, architecture, and API documentation that updates through webhooks whenever you push. You write the parts that need judgment. DocPilot handles the parts that need maintenance. There's a free tier if you want to try it on a single repo first — link in the footer.

Ship documentation that keeps up

Try DocPilot on your repository — free for one repo.

Connect your first repository in about a minute. No credit card. DocPilot writes and maintains the documentation from your code.

Read next