Versioning
Rspress provides powerful versioning capabilities, allowing you to maintain multiple documentation versions for different software releases. This chapter explores how to set up and manage versioned documentation sites.
What is Documentation Versioning?
Versioning Overview
Documentation versioning allows you to maintain separate documentation for each major version of your product:
- Multiple Versions: Maintain docs for v1.0, v2.0, v3.0 simultaneously
- Version Switching: Users can switch between versions
- Version Archiving: Keep old versions for reference
- Independent Content: Each version has its own content and configuration
Why Version Documentation?
User Scenarios:
- Users may be on different software versions
- Upgrades take time, users need access to old docs
- API changes require different documentation
- Features vary between versions
Maintenance Benefits:
- Clear version history
- Easier change tracking
- Better user experience
- Avoid confusion
Basic Version Setup
Directory Structure
Organize multi-version documentation:
docs/
├── v1/ # Version 1.x docs
│ ├── index.md
│ ├── guide/
│ │ ├── getting-started.md
│ │ └── api.md
│ └── examples/
├── v2/ # Version 2.x docs
│ ├── index.md
│ ├── guide/
│ │ ├── getting-started.md
│ │ ├── new-features.md
│ │ └── api.md
│ └── examples/
├── v3/ # Version 3.x (latest)
│ ├── index.md
│ ├── guide/
│ │ ├── getting-started.md
│ │ ├── advanced.md
│ │ └── api.md
│ └── examples/
└── versions.json # Version configurationVersion Configuration
Create versions.json:
{
"latest": "v3",
"versions": [
{
"version": "v3",
"label": "v3.x (Latest)",
"path": "/v3"
},
{
"version": "v2",
"label": "v2.x",
"path": "/v2"
},
{
"version": "v1",
"label": "v1.x",
"path": "/v1"
}
]
}Rspress Configuration
Configure versions in rspress.config.ts:
import { defineConfig } from 'rspress/config';
import versions from './versions.json';
export default defineConfig({
title: 'My Documentation',
// Version configuration
themeConfig: {
// Add version selector
versioning: {
latestVersion: versions.latest,
versions: versions.versions,
},
// Configure navigation for each version
nav: [
{ text: 'Home', link: '/' },
{ text: 'Guide', link: `/${versions.latest}/guide/` },
{ text: 'API', link: `/${versions.latest}/api/` },
{
text: `Version: ${versions.latest}`,
items: versions.versions.map(v => ({
text: v.label,
link: v.path,
})),
},
],
},
});Version Selector
Built-in Version Selector
Rspress provides a built-in version selector component:
export default defineConfig({
themeConfig: {
// Enable version selector
versioning: {
enabled: true,
latestVersion: 'v3',
versions: [
{ version: 'v3', label: 'v3.x (Latest)' },
{ version: 'v2', label: 'v2.x' },
{ version: 'v1', label: 'v1.x (LTS)' },
],
// Version selector position
position: 'navbar', // or 'sidebar'
},
},
});Custom Version Selector
Create a custom version switcher component:
// components/VersionSelector.tsx
import React from 'react';
import { useLocation } from 'rspress/runtime';
import versions from '../versions.json';
export function VersionSelector() {
const location = useLocation();
const currentVersion = location.pathname.split('/')[1] || versions.latest;
const handleVersionChange = (version: string) => {
const currentPath = location.pathname.replace(`/${currentVersion}`, `/${version}`);
window.location.href = currentPath;
};
return (
<div className="version-selector">
<label htmlFor="version-select">Version:</label>
<select
id="version-select"
value={currentVersion}
onChange={(e) => handleVersionChange(e.target.value)}
className="version-dropdown"
>
{versions.versions.map((v) => (
<option key={v.version} value={v.version}>
{v.label}
</option>
))}
</select>
</div>
);
}Style the version selector:
/* styles/version-selector.css */
.version-selector {
display: flex;
align-items: center;
gap: 0.5rem;
padding: 0.5rem;
}
.version-selector label {
font-size: 0.875rem;
color: var(--rp-c-text-2);
}
.version-dropdown {
padding: 0.375rem 0.75rem;
border: 1px solid var(--rp-c-border);
border-radius: 6px;
background: var(--rp-c-bg);
color: var(--rp-c-text-1);
font-size: 0.875rem;
cursor: pointer;
transition: all 0.3s;
}
.version-dropdown:hover {
border-color: var(--rp-c-brand);
}
.version-dropdown:focus {
outline: none;
border-color: var(--rp-c-brand);
box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.1);
}Version Banners
Outdated Version Warning
Add warning banners for old versions:
// components/VersionBanner.tsx
import React from 'react';
import { useLocation } from 'rspress/runtime';
import versions from '../versions.json';
export function VersionBanner() {
const location = useLocation();
const currentVersion = location.pathname.split('/')[1];
const isLatest = currentVersion === versions.latest;
if (isLatest) {
return null;
}
const latestVersionInfo = versions.versions.find(
v => v.version === versions.latest
);
return (
<div className="version-banner warning">
<div className="banner-content">
<span className="banner-icon">⚠️</span>
<span className="banner-text">
You are viewing docs for <strong>{currentVersion}</strong>.
The latest version is{' '}
<a href={latestVersionInfo?.path}>
{latestVersionInfo?.label}
</a>
.
</span>
</div>
</div>
);
}Style the banner:
/* styles/version-banner.css */
.version-banner {
padding: 1rem;
margin-bottom: 2rem;
border-radius: 8px;
background: #fff3cd;
border: 1px solid #ffc107;
color: #856404;
}
.version-banner.warning {
background: #fff3cd;
border-color: #ffc107;
color: #856404;
}
.version-banner.info {
background: #d1ecf1;
border-color: #17a2b8;
color: #0c5460;
}
.banner-content {
display: flex;
align-items: center;
gap: 0.75rem;
}
.banner-icon {
font-size: 1.5rem;
flex-shrink: 0;
}
.banner-text {
line-height: 1.6;
}
.banner-text a {
color: inherit;
text-decoration: underline;
font-weight: 600;
}
.banner-text a:hover {
opacity: 0.8;
}Version Navigation
Per-Version Sidebars
Configure different sidebars for different versions:
export default defineConfig({
themeConfig: {
sidebar: {
// v3 sidebar
'/v3/': [
{
text: 'Getting Started',
items: [
{ text: 'Introduction', link: '/v3/guide/introduction' },
{ text: 'Quick Start', link: '/v3/guide/getting-started' },
{ text: 'New Features', link: '/v3/guide/new-features' },
],
},
{
text: 'API',
items: [
{ text: 'API Reference', link: '/v3/api/reference' },
{ text: 'Advanced Usage', link: '/v3/api/advanced' },
],
},
],
// v2 sidebar
'/v2/': [
{
text: 'Getting Started',
items: [
{ text: 'Introduction', link: '/v2/guide/introduction' },
{ text: 'Quick Start', link: '/v2/guide/getting-started' },
],
},
{
text: 'API',
items: [
{ text: 'API Reference', link: '/v2/api/reference' },
],
},
],
// v1 sidebar
'/v1/': [
{
text: 'Documentation',
items: [
{ text: 'Introduction', link: '/v1/guide/introduction' },
{ text: 'API', link: '/v1/api/reference' },
],
},
],
},
},
});Version-Specific Links
Maintain correct links within each version:
<!-- v3/guide/introduction.md -->
---
title: Introduction
---
# Introduction to v3
Welcome to version 3!
## Next Steps
- [Quick Start](./getting-started.md)
- [New Features](./new-features.md)
- [API Reference](/v3/api/reference)
## Migrating from v2
See our [Migration Guide](./migration-from-v2.md).Version Management Workflow
Creating a New Version
When releasing a new major version:
- Copy Current Docs
# Copy v3 to v4
cp -r docs/v3 docs/v4
# Mark v3 as old version
# Update v4 content with new features- Update Version Config
{
"latest": "v4",
"versions": [
{
"version": "v4",
"label": "v4.x (Latest)",
"path": "/v4"
},
{
"version": "v3",
"label": "v3.x",
"path": "/v3"
},
{
"version": "v2",
"label": "v2.x (Archived)",
"path": "/v2"
}
]
}- Update Config File
export default defineConfig({
themeConfig: {
versioning: {
latestVersion: 'v4',
// ...update version list
},
},
});Maintaining Multiple Versions
Best Practices:
- Major Updates: Only update latest version
- Critical Fixes: Backport to supported versions
- Security Updates: Update all active versions
- Archiving: Mark very old versions as archived
# Example workflow
git checkout main # Latest version (v4)
# Make changes...
git checkout v3-docs # Supported version
# Backport important fixes...
git checkout v2-archived # Critical security fixes onlyLong-Term Support (LTS)
Marking LTS Versions
Indicate which versions are LTS:
{
"latest": "v4",
"versions": [
{
"version": "v4",
"label": "v4.x (Latest)",
"path": "/v4",
"lts": false
},
{
"version": "v3",
"label": "v3.x (LTS)",
"path": "/v3",
"lts": true,
"endOfLife": "2025-12-31"
},
{
"version": "v2",
"label": "v2.x (EOL)",
"path": "/v2",
"lts": false,
"endOfLife": "2024-06-30"
}
]
}LTS Banner
Display LTS information:
export function LTSBanner({ version }) {
const versionInfo = versions.versions.find(v => v.version === version);
if (!versionInfo) return null;
if (versionInfo.lts) {
return (
<div className="version-banner info">
<span className="banner-icon">✅</span>
<span className="banner-text">
This version is LTS (Long Term Support). Supported until{' '}
{new Date(versionInfo.endOfLife).toLocaleDateString()}.
</span>
</div>
);
}
if (versionInfo.endOfLife && new Date(versionInfo.endOfLife) < new Date()) {
return (
<div className="version-banner warning">
<span className="banner-icon">⚠️</span>
<span className="banner-text">
This version has reached End of Life (EOL) and no longer receives updates.
</span>
</div>
);
}
return null;
}Version-Specific Features
Feature Flags
Show content based on version:
import { VersionFeature } from '../components/VersionFeature';
# API Reference
<VersionFeature minVersion="v3">
## New Async API
v3 introduces a new Promise-based API:
`````javascript
// Available in v3+
const result = await api.fetchData();
```
</VersionFeature>
<VersionFeature maxVersion="v2">
## Legacy Callback API
v2 and earlier use callbacks:
```javascript
// v2 and earlier
api.fetchData((error, result) => {
if (error) {
console.error(error);
}
});
```
</VersionFeature>
```
Implement VersionFeature component:
```tsx
// components/VersionFeature.tsx
import React from 'react';
import { useLocation } from 'rspress/runtime';
interface VersionFeatureProps {
minVersion?: string;
maxVersion?: string;
children: React.ReactNode;
}
export function VersionFeature({
minVersion,
maxVersion,
children,
}: VersionFeatureProps) {
const location = useLocation();
const currentVersion = location.pathname.split('/')[1];
// Simple version comparison
const versionNumber = (v: string) => parseInt(v.replace('v', ''), 10);
const current = versionNumber(currentVersion);
if (minVersion && current < versionNumber(minVersion)) {
return null;
}
if (maxVersion && current > versionNumber(maxVersion)) {
return null;
}
return <>{children}</>;
}
```
## Version Redirects
### Auto-Redirect
Redirect root path to latest version:
```typescript
export default defineConfig({
builderConfig: {
html: {
redirects: [
{
from: '/',
to: '/v4/',
},
{
from: '/guide',
to: '/v4/guide/',
},
],
},
},
});
```
### Smart Version Detection
Redirect based on user context:
```tsx
// components/VersionRedirect.tsx
import { useEffect } from 'react';
import { useLocation } from 'rspress/runtime';
export function VersionRedirect() {
const location = useLocation();
useEffect(() => {
// Check if accessing an archived version
const currentVersion = location.pathname.split('/')[1];
const savedVersion = localStorage.getItem('preferredVersion');
// Redirect if user has a preferred version
if (savedVersion && savedVersion !== currentVersion) {
const newPath = location.pathname.replace(
`/${currentVersion}`,
`/${savedVersion}`
);
window.location.href = newPath;
}
}, [location]);
return null;
}
```
## Version Search
### Per-Version Search
Configure version-specific search:
```typescript
export default defineConfig({
themeConfig: {
search: {
versioned: true,
// Create separate search index for each version
indexes: [
{ version: 'v4', path: '/v4' },
{ version: 'v3', path: '/v3' },
{ version: 'v2', path: '/v2' },
],
},
},
});
```
## Best Practices
### Version Naming
1. **Semantic Versioning**: Use v1.x, v2.x, v3.x
2. **Clear Labels**: "v3.x (Latest)", "v2.x (LTS)", "v1.x (Archived)"
3. **Consistency**: Use same naming across all docs
### Content Management
1. **Keep in Sync**: Regularly update all supported versions
2. **Clear Migration Guides**: Provide migration paths between versions
3. **Highlight Changes**: Mark new features in each version
4. **Archive Old Versions**: Clearly mark EOL versions
### User Experience
1. **Default to Latest**: New users should see latest docs
2. **Preserve User Choice**: Remember user's selected version
3. **Clear Visual Cues**: Show current version prominently
4. **Easy Switching**: Make version switching effortless
## Automation
### Version Release Script
```bash
#!/bin/bash
# scripts/release-version.sh
NEW_VERSION=$1
CURRENT_VERSION=$(jq -r '.latest' versions.json)
if [ -z "$NEW_VERSION" ]; then
echo "Usage: ./release-version.sh v4"
exit 1
fi
echo "Creating new version: $NEW_VERSION"
# Copy current version
cp -r "docs/$CURRENT_VERSION" "docs/$NEW_VERSION"
# Update versions.json
jq ".latest = \"$NEW_VERSION\"" versions.json > versions.tmp.json
jq ".versions |= [{
version: \"$NEW_VERSION\",
label: \"$NEW_VERSION.x (Latest)\",
path: \"/$NEW_VERSION\"
}] + ." versions.tmp.json > versions.json
rm versions.tmp.json
echo "✅ Version $NEW_VERSION created"
echo "Now update content in docs/$NEW_VERSION"
```
### Version Archive Script
```bash
#!/bin/bash
# scripts/archive-version.sh
VERSION=$1
if [ -z "$VERSION" ]; then
echo "Usage: ./archive-version.sh v2"
exit 1
fi
echo "Archiving version: $VERSION"
# Update version label
jq "(.versions[] | select(.version == \"$VERSION\") | .label) |= . + \" (Archived)\"" \
versions.json > versions.tmp.json
mv versions.tmp.json versions.json
echo "✅ Version $VERSION archived"
```
## Troubleshooting
### Broken Version Links
**Issue**: Links point to wrong version
**Solution**:
```markdown
<!-- ✅ Use absolute paths -->
[API Reference](/v3/api/reference)
<!-- ❌ Avoid relative paths across versions -->
[API Reference](../../v2/api/reference)
```
### Version Selector Not Showing
**Issue**: Version selector doesn't appear
**Check**:
1. `versions.json` is properly formatted
2. Versioning enabled in config
3. At least 2 versions configured
### Search Shows All Versions
**Issue**: Search results mix all versions
**Solution**:
```typescript
export default defineConfig({
themeConfig: {
search: {
versioned: true, // Enable versioned search
},
},
});
```
---
## Next Steps
- Explore [Built-in Components](./built-in-components.md)
- Learn about [Build Extensions](./build-extensions.md)
- Read about [Custom Search](./custom-search.md)
---
::: tip Best Practices
- Always maintain at least one LTS version
- Provide clear migration guides for each version
- Automate version creation process
- Keep version URL structure consistent
- Add clear warning banners for old versions
:::
::: warning Common Pitfalls
- Don't forget to update internal links
- Don't mix content between versions
- Don't maintain all versions indefinitely
- Don't use ambiguous version labels
- Don't forget to update search indexes
:::
::: info Resources
- [Semantic Versioning](https://semver.org/)
- [Documentation Versioning Best Practices](https://www.writethedocs.org/)
- [Rspress Configuration Reference](https://rspress.dev/api/config)
:::