Monorepos and workspaces
Maintain reproducible monorepos with Bun Workspaces, Catalogs, isolated installs, and filters
Last updated on
Last verified: 2026-08-02 with Bun 1.3.14.
Decide whether you need an orchestrator
| Repository shape | Starting point |
|---|---|
| A few packages with simple scripts | Bun Workspaces only |
| Medium web monorepo that needs caching | Bun Workspaces + Turborepo |
| Enterprise boundaries, generators, and project graphs | Evaluate Nx |
| TypeScript plus Rust, Go, or other languages | Evaluate moon or the organization's existing build system |
Bun owns dependencies, workspaces, and script execution. A task graph, remote cache, or polyglot toolchain supplied by Turborepo, Nx, or moon is a separate responsibility.
Root configuration
{
"name": "acme",
"private": true,
"packageManager": "bun@1.3.14",
"workspaces": {
"packages": ["apps/*", "packages/*"],
"catalog": {
"typescript": "6.0.3",
"zod": "4.1.8"
}
},
"scripts": {
"typecheck": "bun run --filter '*' typecheck",
"test": "bun run --filter '*' test",
"build": "bun run --filter '*' build"
}
}Third-party versions above are the page's verification snapshot, not permanent latest recommendations. A Catalog update affects every referencing workspace and should be reviewed as a repository-wide dependency change.
Reference the Catalog and an internal package from a child manifest:
{
"name": "@acme/api",
"private": true,
"dependencies": {
"@acme/contracts": "workspace:*",
"zod": "catalog:"
}
}Bun resolves workspace: and catalog: to normal versions when publishing public packages. Inspect the final manifest and tarball before release.
Prefer isolated installs for new monorepos
[install]
linker = "isolated"The isolated linker lets packages access only declared dependencies, exposing phantom dependencies earlier. If an older generator or native package requires a flat node_modules, record the failure and deliberately move that repository to hoisted; do not alternate modes unpredictably.
Filter installs and scripts
bun install --filter './apps/api'
bun run --filter '@acme/*' typecheck
bun run --filter '*' test
bun ciFilters reduce local work, but merge gates still need to verify every affected workspace. Use a task orchestrator when tasks depend on one another or require remote caching rather than relying on directory order.
Recommended boundaries
apps/
web/ # UI and framework boundary
api/ # HTTP and MCP entry points
worker/ # asynchronous work
packages/
core/ # pure business rules; no direct Bun API dependency
contracts/ # schemas, DTOs, RPC/OpenAPI types
database/ # data access and migrations
config/ # validated configuration loading
observability/ # logs, traces, and metricsKeep core as portable TypeScript. Place Bun.SQL, Redis, S3, and Bun.serve in application or adapter layers. This retains Bun-native capabilities while keeping business rules easy to unit test.
CI and release gates
- Install the exact Bun version the team has validated.
- Run
bun ciagainst the root manifest andbun.lock. - Check that cross-workspace imports are declared.
- Run affected tasks, then the full graph on the main branch.
- Inspect published manifests after
workspace:andcatalog:conversion. - Install and test native dependencies on the target OS and CPU architecture.
Keep one dependency source of truth
Do not maintain Bun, npm, pnpm, or Yarn lockfiles indefinitely in one repository. Multiple runtimes may coexist, but dependency resolution and publishing must have one explicit owner.
Official references: Workspaces, Catalogs, and bun install.