Versioning
ShellDocs can serve several versions of your docs side by side. Each version is a folder of content. Readers switch with a version selector, and the sidebar, search, breadcrumb and prev/next links stay inside the version they are reading.
Lay out the content
Give each version its own folder under content/docs. Pages that are the same for every version, such as a changelog, stay outside.
-
content
-
docs
- changelog.mdUnversioned
-
v2.0
- meta.json
- introduction.md
- cli
-
v1.9.1
- meta.json
- introduction.md
- cli
-
docs
A version folder is an ordinary content folder. Its meta.json orders its pages, and its title is the label shown where the folder is named.
Register the versions
builder.Services.AddShellDocs(o =>
{
o.AddVersion("v2.0", "v2.0.0", "/docs/v2.0", "Current stable", latest: true);
o.AddVersion("v1.9.1", "v1.9.1", "/docs/v1.9.1", "Previous release");
});
| Prop | Type | Default | Description |
|---|---|---|---|
idRequired |
string |
— | Identifier for the version. Replaces the version token in package root URLs. |
labelRequired |
string |
— | Text shown in the selector. |
rootUrlRequired |
string |
— | URL of the version folder. |
description |
string? |
— | Second line in the selector menu. |
latest |
bool |
false |
Marks the version new readers land on. Shown with a latest badge. |
Which version is current
The current version is the one whose root URL is a prefix of the page's path, matched by whole segments. On a page outside every version folder, it is the version marked latest, or the first one registered when none is.
What changes once versions exist
| Prop | Type | Default | Description |
|---|---|---|---|
Version selector |
chrome |
— | Appears under the package selector in the sidebar, and in the header for the TopNav layout. Hidden with fewer than two versions. |
Sidebar |
scoped |
— | Inside a version, lists only that version's pages. Outside one, version folders are left out because the selector covers them. |
Prev / next |
scoped |
— | Never crosses a version boundary. |
Search |
scoped |
— | Shows the current version plus pages outside every version. |
Breadcrumb |
scoped |
— | Leaves the version folder out of the trail. |
With no versions registered, none of this applies and the site behaves as before.
Switching versions
Each option in the selector is a plain link. It goes to the first of these that exists:
- The same page in the target version.
- The current package's root in the target version.
- The target version's first page.
Because the options are links, the selector works on a static export.
Versioned packages
If you use the package selector, put the {version} token in a package's root URL. It resolves to the current version's id, so switching package keeps the reader in the same version.
o.AddPackage("core", "MyLib.Core", "The core library.", "/docs/{version}/core");
o.AddPackage("cli", "MyLib.CLI", "The command line.", "/docs/{version}/cli");
A package root that has no index.md links to its first page.
Unversioned URLs
A URL with no version in it that matches a page in the latest version redirects there: /docs/cli/dev goes to /docs/v2.0/cli/dev. Links from before you adopted versions keep working. A version root such as /docs/v2.0 redirects to its first page. See Redirects.
Dots in version names
Folder names with dots, such as v0.2.1, keep their dots in every URL. One thing to know: a route written as /docs/{*Path:nonfile}, which is what shelldocs init scaffolds, does not match a URL whose last segment contains a dot. Pages under the version are fine. The bare root /docs/v0.2.1 is handled by the redirect middleware before routing, so it works as long as redirects are enabled.
Adding a new version
- Copy the latest folder
Copy
content/docs/v2.0tocontent/docs/v2.1and update the pages that changed. - Register it as latest
Add an
AddVersioncall for the new version withlatest: trueand remove the flag from the previous one. - Redirect anything you renamed
If a page moved or a version folder was renamed, add an
AddRedirectrule so old links still land.