Skip to content
Back to Knowledge Base

Bun Workspaces: Setup, Commands, and Best Practices

Bun workspaces let you manage multiple packages in a single repository (or a monorepo) using the same workspaces field npm and Yarn read. bun install resolves every package in a single pass, dedupes shared dependencies to the root node_modules, and links local packages declared with the workspace: protocol.

For the full configuration reference, see the Bun workspaces documentation.

A Bun workspace is a repository whose root package.json has a workspaces field listing the directories that hold package.json files. Bun supports full glob syntax here, including negative patterns like !**/excluded/**:

package.json
{
"name": "my-workspace",
"private": true,
"workspaces": ["apps/*", "packages/*"],
}

Every directory matched by those globs that contains a package.json becomes a workspace package. A common layout separates applications from shared packages:

  • Directorymy-workspace/
    • Directoryapps/
      • Directoryweb/
        • package.json
    • Directorypackages/
      • Directoryshared-ui/
        • package.json
    • package.json

To depend on another package in the workspace, reference it with the workspace: protocol so Bun resolves it to the local package. Bun supports workspace:*, workspace:^, and workspace:~, and replaces them with real semver versions on publish:

apps/web/package.json
{
"name": "web",
"dependencies": {
"react": "^19.0.0",
"@my-workspace/shared-ui": "workspace:*",
},
}

Run bun install once at the root to install every package's dependencies and link the internal ones.

Install every package with one bun install

Section titled “Install every package with one bun install”

A single bun install at the root installs and dedupes dependencies for all workspaces, so shared packages exist once in the root node_modules. Install speed is the headline Bun feature: per the Bun team's benchmarks, bun install runs up to 28x faster than npm install, which makes full reinstalls in CI and fresh clones noticeably cheaper in a workspace with many packages.

The --filter flag narrows both installs and script runs to matching packages. For bun run, place --filter before the script name:

Terminal window
bun run --filter '*' build # run build in every package
bun run --filter web build # run build in a single package
bun install --filter 'pkg-*' # install deps only for matching packages

Filters accept globs and compose: pass --filter multiple times, and prefix a pattern with ! to exclude it, as in bun install --filter 'pkg-*' --filter '!pkg-c'.

Bun workspaces are the newest of the four implementations. Setup, linking, the workspace: protocol, and --filter cover the everyday workflows, but there's no filtering by dependency relationship or by what changed in git, which the pnpm --filter flag offers. Bun workspaces also have less production mileage overall, and some ecosystem tools expect an npm, Yarn, or pnpm lockfile rather than the Bun lockfile.

If your workspace leans on publishing workflows or unusual install hooks, test those paths before migrating and check the Bun issue tracker for open workspace issues.

Do Bun workspaces replace a monorepo tool?

Section titled “Do Bun workspaces replace a monorepo tool?”

No. Bun workspaces make installs fast and link local packages, but they don't cache task results or detect which projects a commit affects, so CI reruns every task on every push no matter how fast the install was.

When that becomes the bottleneck, add Nx on top without changing how Bun works:

Terminal window
npx nx@latest init

Your existing package.json scripts keep working and Bun keeps managing installs.

Before Nx, Bun runs a script across packages, but it runs every task every time and has no notion of which packages a change affects:

Terminal window
bun run --filter '*' build # every package
bun run --filter web build # a single package

After nx init, run the same scripts through Nx:

Terminal window
nx run-many -t build # every project
nx build web # a single project
nx affected -t build # only projects touched by your changes

The first run executes your scripts. A second run with no changes is restored from the cache, and nx affected skips the projects your change does not touch.

nx init writes an nx.json with targetDefaults that control how targets behave:

nx.json
{
"targetDefaults": {
"build": {
"cache": true,
"dependsOn": ["^build"],
},
"dev": {
"continuous": true,
},
},
}

cache: true makes a target cacheable: Nx hashes each project's inputs (source files, dependencies, and config) and restores its outputs from the cache when nothing has changed. Nothing is cached unless you opt in, so you stay in control. dependsOn: ["^build"] builds a project's dependencies first. continuous: true marks tasks that don't exit, like dev servers and watchers, so tasks that depend on them don't wait for them to complete.

Nx Cloud adds more ways to speed up CI for a Bun workspace: remote caching shares the cache across CI runs and teammates, Nx Agents distribute tasks across machines, and self-healing CI proposes fixes when tasks fail. For the full walkthrough, see Adding Nx to an existing monorepo and CI setup.

Working with a different package manager? See pnpm workspaces, npm workspaces, or Yarn workspaces. New to monorepos? Start with what a monorepo is and why teams use one.

Last updated: