How to Implement Versioning for Docusaurus Documentation: A Complete Guide
Docusaurus provides a built-in versioning system that creates immutable snapshots of your documentation, allowing you to freeze released versions while maintaining a "next" version for ongoing development.
Implementing versioning for Docusaurus documentation requires understanding the CLI tools, configuration options in docusaurus.config.js, and the internal metadata system that powers the versions UI. The facebook/docusaurus repository contains a robust versioning core within the docs plugin that handles path generation, banner display, and sidebar management automatically.
How Docusaurus Versioning Works
The versioning system in facebook/docusaurus operates through three coordinated mechanisms: the CLI for snapshotting documentation, the plugin configuration for customizing behavior, and the React components for rendering the versions UI.
At the core, the system relies on functions in packages/docusaurus-plugin-content-docs/src/versions/version.ts. The readVersionsMetadata function validates your versions.json file and builds metadata objects, while createVersionMetadata computes the URL paths, edit links, and banner settings for each version. The getVersionPathPart function specifically determines whether a version serves from /, /next, or a version-specific subdirectory like /1.2.0.
When you create a version, Docusaurus:
- Copies the current
docs/folder toversioned_docs/version-[name]/ - Generates a sidebar snapshot at
versioned_sidebars/version-[name]-sidebars.json - Appends the version name to
versions.json
Step-by-Step Implementation
1. Create a New Version Using the CLI
To freeze your current documentation as a new version, run the Docusaurus CLI command from your project root:
npm run docusaurus docs:version 1.2.0
This command performs three operations automatically:
- Copies the entire
docs/directory toversioned_docs/version-1.2.0/ - Creates
versioned_sidebars/version-1.2.0-sidebars.jsonbased on your current sidebar configuration - Adds
"1.2.0"to theversions.jsonfile
After running this command, your file structure will include:
project-root/
├── docs/ # Next (unreleased) documentation
├── versioned_docs/
│ └── version-1.2.0/ # Frozen snapshot
├── versioned_sidebars/
│ └── version-1.2.0-sidebars.json
└── versions.json # ["1.2.0"]
Source reference: Official versioning guide at website/docs/guides/docs/versioning.mdx lines 96-110.
2. Configure Version Behavior in docusaurus.config.js
Add the docs configuration object to your preset settings to control routing, labels, and banners. This example configures version 1.2.0 as the default while maintaining a "Next" version for unreleased features:
// docusaurus.config.js
module.exports = {
presets: [
[
'@docusaurus/preset-classic',
{
docs: {
// Routes /docs to this version
lastVersion: '1.2.0',
// Include the ./docs folder as a "next" version
includeCurrentVersion: true,
// Per-version customization
versions: {
current: {
label: 'Next',
path: 'next',
banner: 'unreleased',
},
'1.2.0': {
label: '1.2.0 (stable)',
path: '',
banner: 'none',
},
'1.1.0': {
label: '1.1.0',
banner: 'unmaintained',
},
},
},
},
],
],
};
Key configuration options:
- lastVersion: Defines which version serves at the
/docsbase path - includeCurrentVersion: Boolean to include or hide the
./docsfolder (the "next" version) - versions: Object mapping version names to their display properties including
label,path,banner, andbadge
3. Customize the Versions Page UI
The default versions page (/versions) uses React hooks to display available documentation versions. In website/src/pages/versions.tsx, the component consumes metadata through useVersions and useLatestVersion hooks:
import {useVersions, useLatestVersion} from '@theme/hooks/useDocs';
function VersionsPage() {
const versions = useVersions('default');
const latestVersion = useLatestVersion('default');
return (
<table>
<tbody>
{versions.map(version => (
<tr key={version.name}>
<th>{version.label}</th>
<td>
<Link to={version.path}>Documentation</Link>
</td>
<td>
<Link to={`${REPO_URL}/releases/tag/v${version.name}`}>
Release Notes
</Link>
</td>
</tr>
))}
</tbody>
</table>
);
}
To customize release note URLs for specific versions, modify the URL generation logic:
function getReleaseNotesUrl(version) {
if (version.name === '2.x') {
return 'https://github.com/facebook/docusaurus/blob/main/CHANGELOG-v2.md';
}
return `${REPO_URL}/releases/tag/v${version.name}`;
}
Source file: website/src/pages/versions.tsx
Versioning Configuration Options
The docusaurus-plugin-content-docs package exposes granular controls for each version. When the createVersionMetadata function processes your configuration (source: packages/docusaurus-plugin-content-docs/src/versions/version.ts lines 81-115), it evaluates these properties:
- path: The URL segment (e.g.,
next,1.0, or empty string for root) - label: The display name in the version dropdown
- banner: Accepts
'unreleased','unmaintained', or'none'to display informational banners - badge: Boolean to show a version badge on each page
- className: Custom CSS class added to the document container
Example configuration for a legacy version with warnings:
versions: {
'1.0.0': {
label: '1.0.0 (Legacy)',
path: '1.0',
banner: 'unmaintained',
badge: true,
}
}
Versioning Internals and File Structure
Understanding the internal file structure helps troubleshoot versioning issues. The readVersionsMetadata function in packages/docusaurus-plugin-content-docs/src/versions/version.ts (lines 49-73) validates your setup by checking:
- That
versions.jsonexists and contains valid version names - That corresponding folders exist in
versioned_docs/ - That sidebar files exist in
versioned_sidebars/
The system generates routes dynamically based on the getVersionPathPart logic (lines 66-78), which constructs URL patterns like:
/docs/for the version specified inlastVersion/docs/next/for the current version (when configured)/docs/1.2.0/for specific versioned paths
Summary
- Use the CLI
npm run docusaurus docs:version [name]to create immutable documentation snapshots inversioned_docs/ - Configure routing via
lastVersionandpathoptions indocusaurus.config.jsto control which version serves from/docs - Manage lifecycle states using the
bannerproperty to mark versions as'unreleased'or'unmaintained' - Customize UI by modifying
website/src/pages/versions.tsxand using theuseVersionshook to access metadata - Understand the core logic in
packages/docusaurus-plugin-content-docs/src/versions/version.tsfor advanced debugging
Frequently Asked Questions
How do I create a new version in Docusaurus?
Run the CLI command npm run docusaurus docs:version 1.0.0 from your project root. This copies your current docs/ folder to versioned_docs/version-1.0.0/, creates a corresponding sidebar file in versioned_sidebars/, and updates versions.json. The version immediately becomes available at /docs/1.0.0/ unless you customize the path in your configuration.
How do I hide the "next" (unreleased) version from my site?
Set includeCurrentVersion: false in your docs configuration within docusaurus.config.js. This prevents Docusaurus from serving the ./docs folder as a version, effectively hiding your work-in-progress documentation from readers while keeping it available in your repository.
How do I mark a version as unmaintained in Docusaurus?
Add the banner: 'unmaintained' property to the version configuration in docusaurus.config.js. This displays a warning banner at the top of every page in that version, informing users that the documentation is no longer receiving updates. You can also use banner: 'unreleased' for versions that are newer than your stable release.
Where does Docusaurus store versioned documentation files?
Docusaurus stores versioned documentation in three locations: the markdown files reside in versioned_docs/version-[name]/, the sidebar configurations are in versioned_sidebars/version-[name]-sidebars.json, and the version registry is maintained in the versions.json file at your project root. These paths are read by the readVersionsMetadata function during the build process.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →