Scoped Commits in Monorepos
Learn how to use scopes effectively in monorepo projects. Covers package-based scoping, workspace naming conventions, and how to structure commit messages across packages.
Detailed Explanation
Monorepo Commit Scoping
In a monorepo, multiple packages or applications live in a single repository. Scopes become essential for identifying which package is affected by each commit. This enables per-package changelogs, independent versioning, and targeted CI pipelines.
Example Messages
feat(web): add dark mode toggle to settings page
fix(api): resolve memory leak in WebSocket handler
build(shared): upgrade TypeScript to 5.4
Scope Naming Strategies
Package Name as Scope
Use the package directory or npm package name:
packages/
core/ → scope: core
cli/ → scope: cli
web-app/ → scope: web-app
api-server/ → scope: api-server
Abbreviated Scopes
For long package names, use abbreviations agreed upon by the team:
feat(web): ... → packages/web-app
fix(api): ... → packages/api-server
build(sdk): ... → packages/client-sdk
Cross-Package Changes
When a commit affects multiple packages, you have two options:
Omit the scope if the change is truly cross-cutting:
build: upgrade Node.js to v20 across all packagesList affected packages in the body:
refactor: standardize error handling Affected packages: core, api, web Replace custom error classes with shared AppError from @myorg/core in all server-side packages.
Tooling Integration
Tools like lerna, nx, and changesets can use scoped commits to:
- Generate per-package changelogs
- Determine which packages need version bumps
- Trigger package-specific CI pipelines
- Identify affected packages for selective testing
Use Case
You maintain a monorepo with separate packages for a web frontend, an API server, and a shared utility library. You have fixed a bug in the API server's authentication middleware and need a commit message that clearly identifies which package was modified, so your CI pipeline only runs tests for the affected package.