workspaces in package.json, making it straightforward to develop a monorepo composed of several independent packages.
A typical monorepo structure looks like this:
Configuring workspaces
Declare workspaces in the rootpackage.json using glob patterns:
Bun supports full glob syntax in
"workspaces", including negation patterns. For example: ["packages/**", "!packages/**/test/**"].Referencing workspace packages
Each workspace has its ownpackage.json. Use the workspace: protocol to reference other packages in the monorepo:
workspace: specifiers:
| Specifier | Resolved to on publish |
|---|---|
workspace:* | exact current version, e.g. 1.0.1 |
workspace:^ | ^1.0.1 |
workspace:~ | ~1.0.1 |
workspace:1.0.2 | 1.0.2 (overrides package.json version) |
workspace: specifiers are automatically replaced with the resolved version.
Installing dependencies
Runningbun install from the root installs dependencies for all workspaces. Shared packages are deduplicated and hoisted to the root node_modules.
Fast monorepo installs — Bun installs the Remix monorepo in ~500ms on Linux: 28x faster than npm, 12x faster than Yarn v1, 8x faster than pnpm.
Benefits
- Code splitting: Workspace packages can declare each other as dependencies.
bun installsymlinks local packages instead of downloading from npm. - Deduplication: Shared dependencies are hoisted to the root
node_modules, avoiding redundant installations. - Script execution: Use
--filterto run scripts across multiple packages.
Filtering with --filter
Install dependencies for a subset of workspaces:
Shared versions with Catalogs
When many workspace packages share the same dependency versions, define those versions once in the rootpackage.json using catalogs and reference them with the catalog: protocol.
package.json: