Good docs are a snapshot of the product at one moment. Product ships faster than docs write. Left alone, a docs site becomes a museum — 30% accurate, 70% describing features that were renamed, removed, or replaced. Users can't tell which 30% until they try each instruction.
This guide is about keeping docs fresh without treating maintenance as a second job.
What rots, how fast
Screenshots
Decay rate: months. Any UI redesign invalidates every screenshot in the affected flow. Check quarterly at minimum.
External links
Decay rate: weeks. 5-10% of external links in any large docs site break per year. Quarterly audits catch them.
Version-specific claims
Decay rate: days after a release. "In v2.3 we added..." is accurate for one release cycle, then potentially misleading.
API responses / field names
Decay rate: whenever the API changes. If you're auto-generating from OpenAPI, this stays fresh. If hand-written, it rots silently.
Third-party tool references
Decay rate: unpredictable. "Open Cloudflare's SSL settings" — Cloudflare redesigned the UI last month. You don't know until a user reports confusion.
Copy-paste code examples
Decay rate: with every library upgrade. Does npm install stripe@latest still produce the API from your example? Run examples quarterly.
The staleness signals
How you detect rot without re-reading every page every week:
1. "Last updated" dates
NookDocs shows Last updated: DATE at the bottom of every page, sourced from the last git commit touching the file. Flag pages not updated in 12+ months for review.
# Pages not touched in 12 months
find docs -name "*.mdx" -mtime +365 | head -20Older = more likely stale. Doesn't mean bad — some reference docs stay correct for years. But it's the shortlist for the freshness audit.
2. Broken link reports
Weekly automated run:
# Internal + external link check
lychee --include-file-extensions=mdx docs/Breaks here:
Internal 404s from page renames (should have been redirected) — see redirects.
External 404s from vendor link rot — replace with updated URL or Internet Archive snapshot.
Wire into CI so broken links block the build. Prevents new rot from shipping.
3. Support ticket URLs
Same signal as improving-docs — tickets referencing a specific docs page mean the page didn't answer the user. But ALSO a staleness signal when the complaint pattern is "the instructions don't match the current UI."
Filter support tickets monthly for phrases like:
"the button isn't where it says"
"the setting has moved"
"I don't see the option"
"outdated"
Each is a maintenance-flagged page.
4. Thumbs-down feedback with "outdated"
NookDocs's feedback widget surfaces these in the dashboard. One-click flag.
5. Your own team surprise
When an engineer reads the docs for their own feature and says "wait, this is wrong" — that's a stale page. Capture these immediately; don't trust team memory.
The quarterly freshness audit
Every ~12 weeks, 4-hour block:
List all pages last updated >12 months ago
Output from the find command above. Usually 10-50 pages for a mid-sized docs site.
Skim each page's title + first paragraph
Fast triage. Does the description still match the feature? Is the first paragraph still accurate? ~30 seconds per page.
Deep-read the pages that flagged in triage
Read the whole page. Note specific sentences that look suspicious. Usually 5-15 pages per audit.
Test every code example + link
Copy-paste into a fresh environment. Visit every external link. 80% of updates ship at this step.
Update or retire
Fresh content lands in the same commit that touched the page. Content no longer relevant gets retired — either deleted with a redirect, or kept as-is with a "This page covers v1 behaviour" banner.
Log in a tracker: date, page, change made, age of last update. Patterns emerge — which sections rot fastest, which writers' pages stay accurate longest.
Keeping screenshots current
The most tedious maintenance. Tactics ranked by effort:
Level 1 — manual quarterly recap
Four times a year, open every page with a screenshot, verify against the current UI. Retake stale ones. Takes a day per quarter for a mid-sized site.
Level 2 — annotations only
Don't capture the whole UI; capture a small region with an arrow/circle annotation. Less pixels to rot. When UI moves, re-capture the small region.
Level 3 — Mermaid / diagrams over screenshots
Architectural + conceptual content → Mermaid. Mermaid source doesn't rot with UI redesigns. See media guide.
Level 4 — automated Playwright capture
Script the screenshots. Checked into CI. Re-captured on every build. Roadmap item; not shipping in NookDocs yet but the pattern works today via playwright test --update-snapshots.
Versioning as a maintenance strategy
If a version will be supported for years, don't edit the version-1 docs into version-2 docs — use NookDocs's versioning to keep them separate.
{
"versions": [
{ "version": "v2", "tag": "Latest", "default": true },
{ "version": "v1", "tag": "Deprecated", "status": "deprecated" }
]
}Each version's docs live at its own URL prefix (/v1/... / /v2/...). The default version's URLs canonical; others carry canonical tags back to default. Enables:
Deprecation notices per version without editing the other version's content.
Per-version search (optional).
Clear link from
/v1/rate-limitsto "this page describes the v1 API — see/v2/rate-limitsfor the current behaviour."
When to retire a page
Not every page should live forever. Candidates for retirement:
Features that no longer exist — product was sunset, page doesn't apply anymore.
Tutorials for versions 2+ behind current — maintenance cost exceeds reader value.
Duplicate pages — two pages cover the same topic, one was written while you forgot the other existed.
Pages with no inbound links + near-zero traffic — nobody's reading; no one would notice it gone.
Retirement options:
Hard delete — gone from repo + db + sitemap + llms.txt. Add a redirect so inbound links don't 404.
Hide — frontmatter
hidden: true. Page still renders at its URL; removed from sidebar + search + sitemap. For pages where URLs shouldn't 404 but shouldn't be discoverable.Banner + keep — add a prominent callout: "This page describes behaviour for Acme v1, which reached end-of-life 2025-06-01. See the current docs for v2+ content." Keep the content for readers who land via old links / search results.
The "latest commit" rule
Every page carries an implicit contract: the last git commit on this file is approximately when this content was last verified. Break the rule (e.g. a cosmetic commit that doesn't actually verify) and the Last updated footer lies.
Implication for edits:
Don't bulk-update timestamps without re-reading. If you're bumping the mtime just to avoid the "stale" triage, you're making the triage useless. Actually verify, then commit.
Small fixes are fine. Typo fixes, link updates, one-sentence additions — commit each. Git history becomes a maintenance log.
Avoid mass search-and-replace commits. A commit that touches 50 pages with one find-and-replace marks all 50 as "recently updated" — but didn't actually verify any. Flag these in commit messages so quarterly audits know.
Deprecation process
When a feature gets deprecated:
Mark the page in-situ
Add a banner callout at the top:
<Banner variant="warning">
`colors.primary` is deprecated as of v2.4. Use `colors.light` /
`colors.dark` instead. `colors.primary` continues to work through
v3.0 (sunset 2026-12-01).
</Banner>Update cross-references
Every page linking to the deprecated feature should mention the deprecation inline OR link to the new approach.
Add a migration section
On the page, a clear "## Migrating to replacement" section with before/after examples.
Update changelog
New <Update> entry in /changelog announcing the deprecation + sunset date.
Schedule the retirement
Calendar reminder for sunset date. On that date: hide or redirect the page, remove from nav, announce completion in the changelog.
Common maintenance mistakes
Maintenance tool checklist
Automate what you can:
CI link checker —
lycheeor similar runs on every PR. Broken links fail the build.Sitemap auto-regen — NookDocs does this on every sync.
Deprecation calendar — Google Calendar entry for each sunset date. Ritual > memory.
Quarterly freshness audit reminder — recurring event, non-negotiable.
Feedback widget — always on. Thumbs-down with comment = maintenance signal.
Analytics dashboard — weekly skim for anomalies (bounce spikes, zero-result search growth).
Screenshot naming convention —
component-state-YYYYMM.pngmakes the most stale one obvious in a file browser.
Related
Improving docs — sibling guide on metrics-driven improvement
Versioning — version-based content separation
Redirects — handling URL changes during retirement
Analytics — the in-platform metrics source
Feedback widget — reader-signal collector
Media guide — screenshot discipline