Skip to content

guide

How to version product documentation

Vlad Kuzin
On this page

The forking trap

Here's the pattern almost every team falls into. The product ships v2. You duplicate the documentation: copy the whole space, the whole folder, the whole page tree, and rename it. Now there are two copies. Ship v3, and there are three. A year later a reader emails about a typo. You fix it once and forget the other two copies. The versions drift until nobody trusts which one is right — the opposite of living documentation.

This is the most common way to version documentation. It is also the most expensive. The copying is not the cost. Everything after it is. Every shared instruction now lives in three places. Every fix is three edits, or it is a divergence. The work scales with versions times pages, and almost none of it is new writing. It is maintenance tax on content you already wrote.

Versioning docs well means breaking one link: "a new version" stops meaning "a new copy of everything." Four product versions should not cost four copies of the pages they share.

The two wrong ways to version docs

Before the right model, the two traps:

Duplicate the whole doc set per version. This is the forking trap above. It feels safe, because each version is fully isolated. It also converts every edit into N edits and guarantees drift. Reserve it for versions that have genuinely diverged (more on that below). It is not a default.

Inline version notes forever. The opposite mistake: keep one copy and annotate it. "In 2.0 this button moved to Settings." "Before 3.1, skip this step." A few of these are fine. A hundred of them turn a clean procedure into archaeology. The reader must filter every paragraph for whether it applies. You can never safely delete an old note either. You do not know who is still on that version.

Both fail for the same reason. They treat "which version does this apply to" as a copy decision or a prose decision. It should be a structural one.

What versioned documentation should actually do

"Versioning" hides four different needs that teams routinely conflate. Separate them and each gets easy:

  1. Multiple live versions readers choose between. v3 is current, v2 is still supported, v1 is legacy-but-referenced. Readers need to land on the version matching the product they run.
  2. Content that differs by version, inside one version's docs. A step that changed, a screen that moved, a feature that only exists on 3+. This is variation within a version, not a whole separate doc set.
  3. A frozen record of a shipped version. Once v2 ships, its docs should stay quotable and stable: what shipped, as it shipped. You keep editing the live source underneath.
  4. Drafting the next version without disturbing the live one. You write v4 while v3 sits in customers' hands. The in-progress changes must not leak into published docs.

A folder-per-version answers only #1, and answers it badly. Needs #2 to #4 you solve by hand. The structural approach answers all four from one source.

How to set it up from a single source

Map each need to a mechanism instead of a copy. The table below is the whole model: what forking forces you to do by hand, and the single-source equivalent:

Version needThe forking answerThe single-source mechanism
Live versions readers switch betweenA separate space/folder per versionVersion selector: header dropdown, lands on the same page in the chosen version
Differences inside one versionInline "in 2.0…" notes, or a forked pageConditional content: a version condition shows/hides the passage per build
Version numbers and URLs that changeFind-and-replace across every pageVariables: one token, resolved per build
A frozen record of a shipped versionA copy you promise not to editRelease snapshot: immutable by design, still readable
Drafting the next versionEdit a copy and hope nothing leaksBranching: invisible to the live site until merged

The left column scales with versions × pages. The right column barely scales at all. The rest of this section walks each row.

Express per-version differences as conditions, not copies. Set up a "version" condition dimension (values like v1, v2, v3) and tag the passages that vary. A step that only applies from v3 onward gets a condition. At publish time it appears in the v3 build and vanishes from the v2 build. One topic, every variant, no duplicate files. You can preview each version's output before you ship it. This is need #2, solved structurally: see create conditional content.

Make version numbers variables, not literals. The current version string, the minimum supported OS, the API base URL: anything that changes per release should be a variable token. Never text typed into a hundred pages. Bump it once and every reference updates. Hard-coded "3.2" scattered across the docs is a slower kind of fork.

Give readers a version selector. Publish more than one version of the same content and a dropdown appears in the site header. Switching keeps the reader on the same page in the other version. Someone reading the v2 install guide is one click from the v3 install guide. That is need #1. Confluence and most wikis make you build it by hand, or bolt it on with a paid app.

Snapshot releases to freeze history. When a version ships, capture a frozen snapshot of every topic in it. The published version then stays exactly as it shipped. You keep editing the live source for the next release (need #3). Archived releases stay readable and comparable without being editable. That is exactly what a supported-but-frozen version, or a regulated record, requires. See manage releases.

Branch the next version. To draft v4 while v3 is live, work on a branch of the affected topics. The changes stay invisible to the published site until you merge (need #4). In-progress version work never leaks.

What this looks like in practice

Concretely, picture a product on v3 with v2 still supported. The install guide is 90% identical across both: same prerequisites, same download step, same verification. The 10% that differs is a renamed setting and one extra step that v3 added.

Forked, that is two full install guides. Every change to the shared 90% costs two edits: a new screenshot, a clarified prerequisite. The day you forget is the day v2's guide goes stale.

Single-source, it is one install guide. The renamed setting is a variable. The v3-only step carries a version = v3 condition. A reader on the v2 docs opens the page and the selector offers the jump to v3. The conditioned step is not there. The variable reads the v2 value. Fix the shared prerequisite once and both versions get it. When v3 ships for good, you snapshot the release and its docs freeze exactly as published. Then you start a branch for v4. You never copied the 90% that never needed copying.

That is the difference in one page. The forked version is two artifacts drifting apart. The single-source version is one artifact that already knows which reader is looking.

When you genuinely need separate versions

Single-source isn't dogma. Sometimes a clean break is right:

  • A major rearchitecture. If v4 reorganizes the product so thoroughly that v3 and v4 share almost nothing, conditions stop helping. You are writing two products. Fork it. Let the version selector point at two genuinely separate doc sets.
  • A regulated or contractual archive. If a version's docs must be preserved verbatim for compliance, a frozen release snapshot is the separate version: immutable by design, no live editing to worry about.

The test is simple. Fork when sharing content creates more risk than it saves. That is the exception, never the every-release default. Even then a snapshot beats a hand-copied folder. Nothing can silently edit a snapshot.

Coming from Confluence or a wiki

If you're versioning docs today by copying a space each release, the migration is the relief. A wiki treats every page as a standalone copy, so versioning has to mean duplication. No structural layer says "this paragraph applies to v3." Moving to a CCMS adds that layer. Your existing pages come in intact. From then on, version differences live in conditions and a selector rather than in forked spaces. For the full head-to-head on why a wiki hits this wall, see Topicary vs Confluence.

The shift is from a copy per version to one source that knows which version each piece belongs to. The first scales with how many versions you support. The second barely scales at all.

The short version

  • Stop forking the whole doc set every release; it turns one edit into N edits and guarantees drift.
  • Separate the four needs: live versions to switch between, per-version differences, frozen archives, and next-version drafts.
  • Use structure, not copies: conditions for differences, variables for version strings, a selector for readers, snapshots for history, branches for the next release.
  • Reserve real forks for genuine divergence or regulated archives, and even then, snapshot instead of copy.

A folder per version is a maintenance bill that grows every release. One source with a selector is a fixed cost. If that single-source layer is unfamiliar, start with what a CCMS is. Versioning is one of the clearest reasons teams move to one.

FAQ

Frequently asked

What is versioned documentation?

Versioned documentation is product docs that track more than one version at once: for example, keeping v3 (current), v2 (supported), and v1 (legacy) all readable while a v4 draft is in progress. The hard part is keeping them aligned without maintaining a full copy of every page per version. Done well, readers pick their version from a selector and the writer maintains one source.

How do you document multiple versions of a product without duplicating content?

Don't fork the whole doc set per release. Keep one source and express version differences three ways: conditional content (a 'version' condition shows or hides a passage), variables (the version number or URL as a token resolved per build), and a published version selector readers use to switch versions. You only duplicate a page when a version genuinely diverges.

What's the difference between a version selector and conditional content?

They solve different problems. A version selector is reader-facing: it lets someone reading the v2 docs jump to the same page in the v3 docs. Conditional content is author-facing: within one version, it shows or hides specific passages so a single topic serves every variant. Most doc sets need both, the selector for major versions and conditions for the smaller per-version differences.

How do you archive an old version of documentation?

Snapshot it. When you ship a release, capture a frozen copy of every included topic so the published version stays exactly as it was, even as the live source changes. That archived release stays readable and reachable from the version selector without being editable, which is what a supported-but-frozen version or a regulated record needs. New work continues on the live source.

Should I use a separate space or folder for each documentation version?

Usually no; that's the forking trap. A folder or wiki space per version means every shared page exists N times, and every fix has to be repeated N times or the versions drift. Use a single source with conditions and a version selector instead, and reserve separate copies only for genuine divergence.

Ready to try Topicary?

Start free. No credit card required.