Unified versioning scripts for the Cosmos documentation site (Mintlify). Covers all products: sdk, ibc, evm, cometbft, hub, etc.
Every product has three directory tiers:
| Directory | Purpose | SEO |
|---|---|---|
<product>/next/ |
Active development — unreleased changes | noindex (add manually to MDX front matter) |
<product>/latest/ |
Current stable release — accumulates Google ranking | Indexed, canonical |
<product>/v0.53/ etc. |
Archived releases — preserved for reference | noindex: true + canonical: pointing at latest/ |
Why latest/? A stable URL means SEO equity is never lost on a version bump. When you ship v0.54, the URL /sdk/latest/ stays the same — only the content changes. Archived pages redirect search engines to the equivalent page in latest/.
sdk/
├── next/ ← active development (pre-release)
├── latest/ ← current stable (SEO-indexed)
├── v0.53/ ← archived (noindex + canonical → latest)
├── v0.50/ ← archived
└── v0.47/ ← archived
When a new release is ready to ship, run through these steps in order.
Make sure next/ contains everything that belongs in the new release. Merge any open PRs targeting next/.
cd scripts/versioning
npm run freezeThe script will prompt for:
- Product — e.g.
sdk,ibc - New display version — the label for the outgoing
latest/when it becomes an archive (e.g.v0.54)
What happens internally:
- Reads
versions.jsonto find the currentlatestDisplayVersion(e.g.v0.53) - Copies
latest/→v0.53/(archive) - Rewrites internal links in the archive:
/sdk/latest/→/sdk/v0.53/ - Injects
noindex: true+canonical:into every MDX file in the archive - Copies
next/→latest/(promote) - Rewrites internal links in the new
latest/:/sdk/next/→/sdk/latest/ - Clones the
latestnav entry indocs.jsonto create a newv0.53nav entry - Updates the
latestnav badge to reflect the new display version (v0.54) - Updates
versions.jsonwith newlatestDisplayVersion
Non-interactive:
NON_INTERACTIVE=1 SUBDIR=sdk NEW_DISPLAY_VERSION=v0.54 npm run freezenpx mint devCheck that /sdk/latest/ loads correctly and /sdk/v0.53/ shows the archived notice (if any).
git add -A
git commit -m "docs: freeze sdk v0.53, promote next to latest (v0.54)"
git pushIf existing versioned directories predate the latest/ model (e.g. sdk/v0.50, sdk/v0.47), run tag-archived.js to inject noindex + canonical front matter into those files.
# Tag a single version
node tag-archived.js --product sdk --version v0.50
# Tag all archived versions for a product
node tag-archived.js --product sdk --all
# Tag all archived versions across all products
node tag-archived.js --all-products --all
# Dry-run: see what would change without modifying files
node tag-archived.js --product sdk --all --dry-run
# Override the canonical base URL
node tag-archived.js --product sdk --all --base-url https://docs.cosmos.networkFor each .mdx file in the targeted archive directory:
- Skips files that already have
noindex:in front matter - Checks whether the equivalent page exists in
<product>/latest/- If yes →
canonical: 'https://docs.cosmos.network/<product>/latest/<page>' - If no →
canonical: 'https://docs.cosmos.network/<product>/latest/'(fallback to root)
- If yes →
- Injects
noindex: trueandcanonical:at the top of the front matter block - Writes the file in place
Run this once per product when first setting up the latest/ model, then the freeze script handles archiving automatically going forward.
# Generate changelog for next (all versions)
npm run changelogs -- --product evm --target next
# Generate changelog for specific version directory
npm run changelogs -- --product evm --target v0.5.0
# Generate all changelogs for a product
npm run changelogs -- --product evm --all
# Test without modifying files (output to ./tmp)
npm run changelogs -- --product evm --all --stagingRelease notes are fetched from the GitHub repositories configured in versions.json:
| Product | Repository |
|---|---|
| evm | cosmos/evm |
| sdk | cosmos/cosmos-sdk |
| ibc | cosmos/ibc-go |
| hub | cosmos/gaia |
The top-level versions.json tracks configuration per product.
{
"products": {
"sdk": {
"versions": ["next", "latest", "v0.53", "v0.50", "v0.47"],
"defaultVersion": "latest",
"latestDisplayVersion": "v0.53",
"repository": "cosmos/cosmos-sdk",
"changelogPath": "CHANGELOG.md"
}
}
}Key fields:
- versions — all available version directories (auto-discovered from filesystem and merged)
- defaultVersion — shown to users by default; should be
latestoncelatest/exists - latestDisplayVersion — the human-readable release label shown in the navigation badge (e.g.
v0.53 (Latest)) - repository — GitHub repo for changelog fetching
- changelogPath — path within the repo (default:
CHANGELOG.md)
The next/ directory contains pre-release documentation. It is not blocked by the freeze script — you are responsible for adding noindex: true to pages in next/ if you want to prevent search engines from indexing unreleased content.
To add noindex to all files in a next/ directory:
node tag-archived.js --product sdk --version next --base-url https://docs.cosmos.networkNote: This will set the canonical to
/sdk/latest/for each page, which is correct — it tells Google the authoritative version islatest/.
The freeze script uses Perl (not sed) for link replacement because Perl can skip external URLs while rewriting internal paths:
s{(https?://\S+)|/sdk/next/}{defined($1)?$1:"/sdk/latest/"}geThis pattern:
- Matches a full
https://orhttp://URL → returns it unchanged - Otherwise matches the internal path prefix → replaces it
This prevents GitHub links like https://github.com/cosmos/cosmos-sdk/blob/release/v0.53.x/... from being accidentally rewritten.
| Script | Command | Purpose |
|---|---|---|
version-manager.js |
npm run freeze |
Full version freeze workflow |
tag-archived.js |
node tag-archived.js |
Inject noindex/canonical into archived dirs |
manage-changelogs.js |
npm run changelogs |
Fetch and update release notes |
test-versioning.js |
npm run test |
System validation |
scripts/versioning/
├── README.md # This file
├── GSHEET-SETUP.md # Google Sheets API setup (EVM only)
├── SECURITY-SYNC.md # Security docs sync system
├── version-manager.js # Main freeze orchestration
├── tag-archived.js # Retroactive noindex/canonical injection
├── manage-changelogs.js # Unified changelog management
├── sheets-manager.js # Google Sheets operations (EVM only)
├── test-versioning.js # System testing
├── restructure-navigation.js # Navigation cleanup utility
├── package.json
└── service-account-key.json # Google service account (git-ignored)
- CLAUDE.md — AI assistant context and Mintlify constraints
- GSHEET-SETUP.md — Google Sheets API setup for EVM EIP tables
- Mintlify docs — MDX reference