Changelog
How to maintain a changelog section in your documentation site.
zudo-doc includes a changelog section for tracking release notes and version history. The changelog uses descending sidebar sort so the newest entries always appear at the top.
Directory Structure
Changelog entries live in a dedicated content directory:
src/content/docs/
└── changelog/
├── index.mdx # Category index page (sets desc sort order)
├── 0.2.0.mdx # Newer entry (sidebar_position: 2)
└── 0.1.0.mdx # Older entry (sidebar_position: 1) Category Configuration
The index.mdx file configures descending sort order so newer entries appear first in the sidebar:
---
title: Changelog
sidebar_position: 10
category_sort_order: "desc"
---With category_sort_order: "desc", entries with higher sidebar_position values appear first. This means newer versions naturally sort to the top.
Adding a New Entry
To add a new changelog entry:
Create a new MDX file in
src/named after the version (e.g.,content/ docs/ changelog/ 0.2.0.mdx)Set the
sidebar_positionto a value higher than the previous entryMirror the file in every configured additional-locale directory (for example,
src/andcontent/ docs- ja/ changelog/ src/)content/ docs- de/ changelog/
---
title: "0.2.0"
description: Short summary of this release.
sidebar_position: 2
---
Summary of changes in this release.
### Features
- Feature A
- Feature B
### Bug Fixes
- Fix for issue XTip
Use incrementing sidebar_position values for each new version. Combined with category_sort_order: "desc" in the category's index.mdx, this ensures the newest entry always appears at the top of the sidebar.
Entry Format
Each changelog entry is a standard MDX file. zudo-doc recommends a Keep a Changelog-style structure because those entries can be converted into package-friendly CHANGELOG.md files:
Title: The version number (e.g.,
"0.2.0")Description: A brief summary of the release
Release date: A
Released: YYYY-MM-DDline near the top when the release date is knownContent sections: grouped human-written notes such as Added, Changed, Deprecated, Removed, Fixed, Security, Breaking Changes, Features, and Bug Fixes
Write entries for humans. Do not dump raw git logs into changelog pages; group notable user-facing changes into short bullets.
Generated Package Changelogs
Projects can configure generated changelog outputs with the changelogs field. Each item points at a source directory and an output file:
export default defineConfig(
zudoDoc({
changelogs: [
{
sourceDir: "src/content/docs/changelog",
outputFile: "packages/zudo-doc/CHANGELOG.md",
packageName: "@takazudo/zudo-doc",
},
],
}),
);The MDX files remain the source of truth. The generated CHANGELOG.md is overwritten from those pages and should not be edited by hand. zudo-doc strips frontmatter, imports, exports, JSX tags/components, and MDX comments so the output stays readable as CommonMark in node_modules.
Multiple outputs can be configured by adding more items to the array. This is useful when a monorepo wants separate package changelogs, each generated from its own changelog source directory.
Multiple Changelogs (Multi-Package Projects)
Use a nested changelog when a monorepo publishes several packages independently. The top-level page becomes a landing page, and each package gets its own nested category:
src/content/docs/changelog/
├── index.mdx
├── core/
│ └── index.mdx
└── cli/
└── index.mdx This produces /, /, and /. The landing page lists the package categories and does not use category_sort_order: "desc":
---
title: Changelog
sidebar_position: 10
---
Release notes for every package in this repository.
<CategoryNav category="changelog" />One Page per Package (Default)
By default, the generator creates one index.mdx per package. Keep the complete package history on that page, with ## Unreleased followed by version sections:
---
title: Core
sidebar_position: 1
---
## Unreleased
### Added
- Work in progress.
## 1.0.0
Released: 2026-08-22
### Added
- Initial release.One File per Version
Use separate version files when you also emit a package CHANGELOG.md. In this variant, the package index sets descending order and renders its release files:
src/content/docs/changelog/core/
├── index.mdx
├── 1.1.0.mdx
└── 1.0.0.mdx ---
title: Core
sidebar_position: 1
category_sort_order: "desc"
---
Release notes for the core package.
<CategoryNav category="changelog/core" />Each package directory configured in changelogs must contain non-index, per-release MDX files. Set sourceDir to that package directory, never to the top-level changelog/ landing directory:
changelogs: [
{
sourceDir: "src/content/docs/changelog/core",
outputFile: "packages/core/CHANGELOG.md",
packageName: "@acme/core",
},
{
sourceDir: "src/content/docs/changelog/cli",
outputFile: "packages/cli/CHANGELOG.md",
packageName: "@acme/cli",
},
],The build warns about the landing-directory pitfall when a configured sourceDir yields no release entries but contains subdirectories with MDX files.
Tip
Previous/next pagination runs across the entire changelog section, so it can cross from one package into another. On package boundary pages, set pagination_prev: null or pagination_next: null in frontmatter when that transition would be confusing.
Generate the Layout
Pass a comma-separated package list when scaffolding a project:
pnpm create zudo-doc my-docs --changelog-packages core,cli--changelog-packages implies --changelog. The generator creates the landing page and one package index for each slug, but it does not add a changelogs output configuration. To emit package CHANGELOG.md files, switch those packages to the per-version-file layout and configure one changelogs entry per package.
The version-bump skill keeps one lockstep root version and updates all packages by default, or only the packages you select. It adds a new version section to each selected single-page changelog, or a new per-version file to each selected package using the per-version-file layout. Independent per-package versioning is not supported.
Version Bump Script
zudo-doc includes a scripts/ script that automates version management:
# Bump version and create changelog entry
./scripts/version-bump.sh 0.2.0
# Bump version, create changelog entry, and snapshot current docs
./scripts/version-bump.sh 1.0.0 --snapshotThe script performs the following steps:
Updates the
versionfield inpackage.jsonCreates a changelog entry MDX file in the primary and each configured additional-locale directory
Sets the correct
sidebar_positionautomatically (incremented from existing entries)
Doc Snapshots
When called with --snapshot, the script also archives the current documentation as a versioned snapshot before bumping. This integrates with zudo-doc's versioning system:
Copies
src/tocontent/ docs/ src/content/ docs- v{old}/ Copies each configured additional-locale directory (for example,
src/tocontent/ docs- ja/ src/andcontent/ docs- v{old}- ja/ src/tocontent/ docs- de/ src/)content/ docs- v{old}- de/ Prints the version config entry to add to
src/config/ settings. ts
Note
The --snapshot flag archives the old version's docs, not the new version. After the script runs, src/ represents the new version and the snapshot preserves the previous state.
Version Bump Skill
For Claude Code users, zudo-doc includes a / skill that orchestrates the entire release workflow. Instead of running the script manually, the skill handles everything end-to-end:
Analyzes commits since the last git tag and categorizes them (breaking, features, fixes, other)
Proposes a version bump type (major/minor/patch) based on the changes
Runs
version-bump.shto updatepackage.jsonand create changelog entriesFills in the changelog templates with actual commit details for the primary and each configured locale
Runs
pnpm b4pushto validate the buildCommits, pushes, and waits for CI
Creates a git tag and GitHub release
Guides you through npm publishing (or skips it for private packages)
# Run the skill in Claude Code
/zudo-doc-version-bump
# Or skip the proposal step by specifying the bump type
/zudo-doc-version-bump patchNote
The skill requires at least one v* tag to exist. If this is the first release, create the initial tag manually: git tag v0.1.0 && git push --tags.
Header Navigation
For one changelog, use a flat headerNav item:
headerNav: [
// ...other items
{ label: "Changelog", labelKey: "nav.changelog", path: "/docs/changelog", categoryMatch: "changelog" },
],For multiple package changelogs, make the parent a dropdown. Keep categoryMatch: "changelog" on the parent and omit categoryMatch from its children:
headerNav: [
// ...other items
{
label: "Changelog",
path: "/docs/changelog",
categoryMatch: "changelog",
children: [
{ label: "Core", path: "/docs/changelog/core" },
{ label: "CLI", path: "/docs/changelog/cli" },
],
},
],Nested child active state is path-based, while categoryMatch scopes the sidebar by a single top-level directory. Two or more children that share a categoryMatch can all appear active in server-rendered HTML. A multi-segment value such as "changelog/core" never matches the top-level category and can leave the sidebar empty. The build reports a warning for either mistake. See Header Navigation for the general rule.
i18n
Mirror changelog entries in every configured additional-locale directory (such as src/ and src/) to provide translated release notes. The index.mdx and directory structure should match the primary version.