Monorepo Changelog Generation

Generate changelogs for monorepo projects by using scoped Conventional Commits to identify changes per package or service.

Best Practices

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:

  1. Root-level changelog — A single CHANGELOG.md at the repository root that includes all packages. Scopes distinguish which package each change belongs to.
  2. 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.

Try It — Changelog Generator

Open full tool