Monorepo Changelog Generation
Generate changelogs for monorepo projects by using scoped Conventional Commits to identify changes per package or service.
Detailed Explanation
Changelogs in a Monorepo
Monorepos contain multiple packages, services, or applications in a single repository. The challenge is producing changelogs that are relevant to each package while working from a single commit history.
Using Scopes for Package Identification
The key is consistent use of Conventional Commit scopes that match package names:
feat(web): add user profile page
feat(api): implement GraphQL subscriptions
fix(web): correct mobile navigation
fix(shared): handle null in date formatter
build(api): upgrade Express to v5
Per-Package Filtering
Before pasting commits into the generator, filter for a specific package:
git log --oneline v1.0.0..HEAD | grep -E '\((web|shared)\)'
This extracts only commits scoped to web or shared, producing a focused changelog for the web application.
Generated Output
## [1.3.0] - 2026-02-27
### Added
- **web:** add user profile page
### Fixed
- **web:** correct mobile navigation
- **shared:** handle null in date formatter
Root-Level vs. Package-Level Changelogs
Two strategies exist:
- Root-level changelog — A single CHANGELOG.md at the repository root that includes all packages. Scopes distinguish which package each change belongs to.
- Package-level changelogs — Separate CHANGELOG.md files per package (e.g.,
packages/web/CHANGELOG.md). Each is generated by filtering commits for that package's scope.
Handling Cross-Package Changes
Commits that affect multiple packages can use a combined scope or no scope:
refactor: migrate from CommonJS to ESM across all packages
feat(web,api): add shared error handling middleware
The generator treats multi-scope entries as a single scope string, rendering them as web,api: in the output.
Use Case
Essential for monorepo projects using tools like Turborepo, Nx, or Lerna. Scope-based filtering enables per-package release notes while maintaining a single commit convention across the entire repository.