Skip to content

How to maintain documentation over time

Ownership, change-driven reviews, checks on every pull request, and a plan for retiring pages.

Documentation starts drifting the day it ships. Features change, flags get renamed, an example stops compiling. Nobody decides to let the docs rot; it happens by default, one unreviewed release at a time. Readers follow a stale step, hit an error, and stop trusting the rest of the page.

Maintenance is not a heroic quarterly cleanup. It is a small number of habits wired into the workflow you already have, so that accuracy is the path of least resistance. On Reed that workflow is git: your docs are MDX files and a docs.json in a repository, and every change goes through the same branch-and-review loop as code. That makes most of what follows easier to enforce than it would be anywhere else.

Every section of your docs needs an owner. An owner is not necessarily the person who writes every word. It is the person who is accountable when the page is wrong.

Three models work:

  • Centralized. A docs team or a technical writer owns everything. This fits small products, where one team can hold enough context to keep every page correct.
  • Distributed. Each product or engineering team owns the docs for its own area. This fits large products with specialized domains. It needs a coordinator, or the sections drift apart in tone and structure and nobody notices the gaps between them.
  • Hybrid. A docs team owns the shared spine — the quickstart, navigation, style — and domain teams own the reference and guides for their features.

Pick one and make it visible. Because your docs live in a repository, the obvious place is a CODEOWNERS file: map content/api/ to the API team and content/guides/ to the docs team, and your git host requests the right reviewer on every pull request automatically. Ownership that lives only in someone’s head does not survive a reorg.

The review that catches the most drift is the one triggered by the product change itself.

  • Update docs in the same pull request as the code. The engineer who changed the behavior knows exactly what changed, today. In a month they will not.
  • Put docs on the launch checklist. A feature is not shipped until its page is.
  • Gate user-facing tickets on a docs check. If the behavior a user sees changed, the ticket does not close until someone has confirmed the docs match.

This beats a calendar because the context is fresh and the cost is small. Doing it in the same pull request also means a reviewer sees the code and the prose side by side, which is where contradictions are easiest to spot.

Some content is not tied to any single feature — overviews, concepts, troubleshooting — and it drifts anyway. A light schedule catches that:

  • Monthly: re-read your highest-traffic pages. They affect the most readers, so they earn the most attention.
  • Quarterly: audit the pages that generate support tickets or complaints.
  • Annually: a full pass for outdated examples, superseded approaches, and pages that no longer describe how the product actually works.

“Highest-traffic” assumes you measure traffic. Reed does not, on its own; it emits the script for an analytics provider you configure. See Improving docs.

Automation cannot tell you whether a paragraph is true. It can tell you, on every pull request and without anyone remembering to ask, about the mistakes that are mechanical.

reed check validates docs.json against the schema and runs static checks over your content: navigation entries resolve to real pages, components exist and carry their required props, referenced assets are present. It never touches the network and needs no setup, so it is safe to run in any CI job. Among the diagnostics it reports:

Code Catches
DS-S06 An unknown component — usually a typo, or one pasted from another platform.
DS-A01 An image with no alt text.
DS-A02 An H1 in the page body, or a skipped heading level.
DS-D01 More than 40 components on a single page.

The full list is in Diagnostics. The CI recipe, including the two caches you need to restore for an offline build, is in Offline builds in CI.

reed check validates docs.json and your navigation. It does not check links you write inside page prose, and it does not add your base prefix to them. A link to /quickstart on a site mounted at /docs compiles cleanly and 404s in production.

So add a link check of your own. This site runs a short Node script before every build that scans each .mdx file for markdown link destinations and href attributes, fails on any root-relative link that is missing the base prefix, and fails on any link whose target page file does not exist. It skips inline code, so a page can still show a wrong link as a counter-example. Under eighty lines of script, and a whole class of broken links cannot reach production. See Linking for the linking rules it enforces.

A prose linter such as Vale checks terminology, passive voice and house style on every pull request. It will not make writing good, but it keeps a hundred small inconsistencies from accumulating. Style and tone covers what to encode.

Reed has no “last reviewed” tracker. It does not need one: git already knows when each file last changed. List your oldest pages first:

sh
for f in $(git ls-files 'content/*.mdx'); do
echo "$(git log -1 --format=%cs -- "$f") $f"
done | sort | head -20

An old date is not proof a page is wrong. It is a list of pages nobody has looked at in a while, which is exactly the review queue you want. Run it in a scheduled CI job if you want it to arrive without anyone asking.

If your API reference comes from an OpenAPI spec, regenerate the spec as part of your release pipeline and commit it with the release. A reference rendered from the real spec cannot fall behind the API; one maintained by hand always does.

Incremental edits stop working past a certain point. A page that has absorbed years of caveats and workarounds becomes harder to fix than to replace.

Rewrite, rather than edit, when:

  • readers keep reporting confusion after several rounds of fixes;
  • the page has grown to cover several distinct topics that should be separate pages;
  • the product changed so much that the page’s structure no longer maps to how the feature works;
  • more than half of it is edge cases, exceptions and “unless” clauses.

Start a rewrite with an audit, not a blank file. Write down what is missing, what is misleading, and what is redundant. Then rewrite in a focused sprint, on a branch, and merge it in one pull request so reviewers see the new page as a whole.

A wrong page is worse than a missing one. A missing page sends readers to search or support. A wrong page sends them down a path that fails, and costs you their trust in every other page. If content is inaccurate and you cannot fix it now, take it down.

When you remove or move a page:

  1. Add a redirect. Map the old path to the most relevant current page in redirects in docs.json. Reed writes each into a _redirects file, which Cloudflare Pages and Workers serve as a real 301 or 302. It also writes a page at the old path that meta-refreshes to the new one and carries a canonical link to it, the fallback on hosts that do not apply _redirects, including Netlify unless you add a forced rule. See Redirects.
  2. Fix inbound links. Search your content for the old path and update every link. The link check above fails the build on the ones you miss.
  3. Update navigation. Remove the page from navigation. reed check fails on an entry that no longer resolves, so you cannot forget this step.
  4. Say so in the changelog if the page was widely used. On Reed, a changelog is a page with type: changelog in its frontmatter and one dated ## heading per entry. There is no RSS feed or subscriber notification, so the entry is only as visible as the page.
How do I get engineers to update documentation when they ship?

Make it a requirement, not a request. Put documentation in your definition of done, and put the docs change in the same pull request as the code change. With a CODEOWNERS entry, the right docs reviewer is added to that pull request automatically. Engineers who see that stale docs turn into support tickets routed back to them rarely need a second reminder.

How do I handle documentation for a deprecated feature?

Keep the page, and mark it. Put a warning callout at the top that says the feature is deprecated, when it will be removed, and what to migrate to. Do not delete the page until the feature is actually gone, because readers on older versions still rely on it. Once it is removed, delete the page and redirect its path to the migration guide or the replacement.

What is the minimum viable process for a small team?

Two habits cover most of the value. Update docs in the same pull request as the code, and run reed check plus a prose link check on every pull request. Together they stop the two most common kinds of drift, stale instructions and dead links, without any dedicated tooling. Add scheduled reviews as the product grows.

How do I prioritize documentation debt?

By impact on readers, not by how messy a page feels to the team. A stale page with thousands of monthly views and a steady stream of support tickets outranks an ugly page nobody reads. Rank pages by traffic from your analytics provider, then cross-reference with support ticket topics, and fix the pages readers actually hit.