#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 configuration#Version 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 only#Long-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)
:::