Catalogs
Share common dependency versions across multiple packages in a monorepo
Catalogs share dependency versions across the packages in a monorepo. Rather than repeating the same versions in each workspace package, you define them once in the root package.json and reference them throughout your project.
Overview
Instead of each workspace package specifying its own versions, you:
- Define version catalogs in the root
package.json - Reference those versions with the
catalog:protocol - Update every package at once by changing the version in one place
This matters most in large monorepos where dozens of packages depend on the same versions of key dependencies.
How to Use Catalogs
Directory Structure Example
Consider a monorepo with the following structure:
my-monorepo/
├── package.json
├── bun.lock
└── packages/
├── app/
│ └── package.json
├── ui/
│ └── package.json
└── utils/
└── package.json1. Define Catalogs in Root package.json
In your root-level package.json, add a catalog or catalogs field within the workspaces object:
{
"name": "my-monorepo",
"workspaces": {
"packages": ["packages/*"],
"catalog": {
"react": "^19.0.0",
"react-dom": "^19.0.0"
},
"catalogs": {
"testing": {
"jest": "30.0.0",
"testing-library": "14.0.0"
}
}
}
}catalog and catalogs also work at the top level of package.json.
2. Reference Catalog Versions in Workspace Packages
In your workspace packages, use the catalog: protocol to reference versions:
{
"name": "app",
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:",
"jest": "catalog:testing"
}
}{
"name": "ui",
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:"
},
"devDependencies": {
"jest": "catalog:testing",
"testing-library": "catalog:testing"
}
}3. Run Bun Install
Run bun install to install all dependencies according to the catalog versions.
Catalog vs Catalogs
Bun supports two ways to define catalogs:
-
catalog(singular): A single default catalog for commonly used dependenciespackage.json "catalog": { "react": "^19.0.0", "react-dom": "^19.0.0" }Reference with
catalog::packages/app/package.json "dependencies": { "react": "catalog:" } -
catalogs(plural): Multiple named catalogs for grouping dependenciespackage.json "catalogs": { "testing": { "jest": "30.0.0" }, "ui": { "tailwind": "4.0.0" } }Reference with
catalog:<name>:packages/app/package.json "dependencies": { "jest": "catalog:testing", "tailwind": "catalog:ui" }
Benefits of Using Catalogs
- Consistency: All packages use the same version of critical dependencies
- Maintenance: Update a dependency version in one place instead of across multiple
package.jsonfiles - Clarity: Makes it obvious which dependencies are standardized across your monorepo
- Simplicity: No extra version resolution strategies or external tools
Real-World Example
A larger example, for a React application:
Root package.json
{
"name": "react-monorepo",
"workspaces": {
"packages": ["packages/*"],
"catalog": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router-dom": "^6.15.0"
},
"catalogs": {
"build": {
"webpack": "5.88.2",
"babel": "7.22.10"
},
"testing": {
"jest": "29.6.2",
"react-testing-library": "14.0.0"
}
}
},
"devDependencies": {
"typescript": "5.1.6"
}
}{
"name": "app",
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:",
"react-router-dom": "catalog:",
"@monorepo/ui": "workspace:*",
"@monorepo/utils": "workspace:*"
},
"devDependencies": {
"webpack": "catalog:build",
"babel": "catalog:build",
"jest": "catalog:testing",
"react-testing-library": "catalog:testing"
}
}{
"name": "@monorepo/ui",
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:"
},
"devDependencies": {
"jest": "catalog:testing",
"react-testing-library": "catalog:testing"
}
}{
"name": "@monorepo/utils",
"dependencies": {
"react": "catalog:"
},
"devDependencies": {
"jest": "catalog:testing"
}
}Updating Versions
To update versions across all packages, change the version in the root package.json:
"catalog": {
"react": "^19.1.0", // Updated from ^19.0.0
"react-dom": "^19.1.0" // Updated from ^19.0.0
}Then run bun install to update all packages.
Lockfile Integration
Bun's lockfile tracks catalog versions, so installs are consistent across environments. The lockfile includes:
- The catalog definitions from your package.json
- The resolution of each cataloged dependency
{
"lockfileVersion": 2,
"workspaces": {
"": {
"name": "react-monorepo",
},
"packages/app": {
"name": "app",
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:",
...
},
},
...
},
"catalog": {
"react": "^19.0.0",
"react-dom": "^19.0.0",
...
},
"catalogs": {
"build": {
"webpack": "5.88.2",
...
},
...
},
"packages": {
...
}
}Limitations and Edge Cases
- Catalog references must match a dependency defined in either
catalogor one of the namedcatalogs - Empty strings and whitespace in catalog names are ignored (treated as default catalog)
- Invalid dependency versions in catalogs fail to resolve during
bun install - Catalogs are only available within workspaces; they cannot be used outside the monorepo
Publishing
When you run bun publish or bun pm pack, Bun replaces catalog: references
in your package.json with the resolved version numbers. The published package
includes regular semver strings and no longer depends on your catalog
definitions.