name: bun-workspaces description: | Bun monorepo workspaces - configuration, filtering, dependencies, and multi-package management When user works with Bun monorepos, workspaces, multi-package projects, or mentions bun --filter
Bun Workspaces Agent
What's New in Bun Workspaces (2024-2025)
-
Text-based lockfile:
bun.lockreplaces binarybun.lockb(v1.2+) - Catalogs: Define shared dependency versions once in root package.json
- Dependency-aware filtering: Scripts run in dependency order
- Glob patterns: Full glob syntax with negative patterns
- Automatic lockfile migration: From npm, yarn, pnpm
Performance
Bun workspaces are significantly faster than alternatives:
- 28x faster than npm install
- 12x faster than yarn install (v1)
- 8x faster than pnpm install
Monorepo Structure
my-monorepo/
├── package.json # Root config with workspaces field
├── bun.lock # Single lockfile for all packages
├── bunfig.toml # Optional Bun configuration
├── tsconfig.json # Shared TypeScript config
└── packages/
├── shared/
│ ├── package.json
│ ├── index.ts
│ └── tsconfig.json
├── backend/
│ ├── package.json
│ ├── src/
│ └── tsconfig.json
└── frontend/
├── package.json
├── src/
└── tsconfig.json
Root package.json
{
"name": "my-monorepo",
"private": true,
"workspaces": ["packages/*"],
"scripts": {
"dev": "bun --filter '*' dev",
"build": "bun --filter '*' build",
"test": "bun --filter '*' test",
"typecheck": "bun --filter '*' typecheck"
},
"devDependencies": {
"typescript": "^5.0.0"
}
}
Glob Patterns
{
"workspaces": [
"packages/*",
"apps/*",
"packages/**",
"!packages/**/test/**",
"!packages/deprecated"
]
}
Workspace Protocol
Reference workspace packages in dependencies:
{
"name": "@myorg/backend",
"dependencies": {
"@myorg/shared": "workspace:*"
}
}
Protocol Variants
| Syntax | Meaning | Published As |
|---|---|---|
workspace:* |
Any version | "1.0.0" (actual version) |
workspace:^ |
Caret range | "^1.0.0" |
workspace:~ |
Tilde range | "~1.0.0" |
workspace:1.0.2 |
Exact version | "1.0.2" |
When publishing, workspace: references are replaced with actual versions.
Catalogs
Define shared dependency versions once:
{
"name": "my-monorepo",
"private": true,
"workspaces": ["packages/*"],
"catalog": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"typescript": "^5.0.0",
"zod": "^3.22.0"
}
}
Using Catalog in Workspace
{
"name": "@myorg/frontend",
"dependencies": {
"react": "catalog:",
"react-dom": "catalog:",
"zod": "catalog:"
}
}
Named Catalogs
{
"catalogs": {
"default": {
"typescript": "^5.0.0"
},
"testing": {
"vitest": "^1.0.0",
"playwright": "^1.40.0"
}
}
}
{
"devDependencies": {
"typescript": "catalog:",
"vitest": "catalog:testing"
}
}
Commands
Installing Dependencies
# Install all workspaces
bun install
# Install with frozen lockfile (CI)
bun install --frozen-lockfile
# Generate lockfile only
bun install --lockfile-only
# Filter to specific packages
bun install --filter "pkg-*"
bun install --filter "!pkg-c"
Adding Dependencies
# Add to current workspace
cd packages/backend
bun add express
# Add as dev dependency
bun add -d typescript
# Add with exact version
bun add -E zod@3.22.0
# Add to specific workspace from root
bun add lodash --filter "@myorg/shared"
Running Scripts
# Run in all workspaces
bun --filter '*' dev
# Run in specific package
bun --filter '@myorg/backend' dev
# Run with glob pattern
bun --filter 'pkg-*' build
# Run excluding packages
bun --filter '*' --filter '!@myorg/frontend' test
# Run by path
bun --filter './packages/backend' dev
Script Dependency Order
When packages depend on each other, scripts run in dependency order:
# If @myorg/backend depends on @myorg/shared:
bun --filter '*' build
# Runs: shared build → backend build
Other Commands
# Check outdated dependencies
bun outdated
bun outdated --filter 'pkg-*'
# Update dependencies
bun update
# Remove dependency
bun remove lodash
# List installed packages
bun pm ls
bun pm ls --all
Shared Configuration
TypeScript (tsconfig.json)
Root tsconfig.json:
{
"compilerOptions": {
"strict": true,
"target": "ESNext",
"module": "ESNext",
"moduleResolution": "bundler",
"esModuleInterop": true,
"skipLibCheck": true,
"declaration": true,
"composite": true,
"paths": {
"@myorg/*": ["./packages/*/src"]
}
}
}
Workspace tsconfig.json:
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src"],
"references": [{ "path": "../shared" }]
}
ESLint (eslint.config.js)
// Root eslint.config.js
import baseConfig from "@myorg/eslint-config";
export default [
...baseConfig,
{
ignores: ["**/dist/**", "**/node_modules/**"],
},
];
bunfig.toml Configuration
[install]
# Auto-install missing dependencies
auto = true
# Lifecycle scripts control
lifecycle = ["postinstall"]
[install.lockfile]
# Save text-based lockfile
save = true
# Also generate yarn.lock
print = "yarn"
[install.scopes]
# Registry for scoped packages
"@myorg" = { token = "$NPM_TOKEN", url = "https://npm.pkg.github.com" }
Common Patterns
Shared Library Package
{
"name": "@myorg/shared",
"version": "1.0.0",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./utils": {
"import": "./dist/utils.js",
"types": "./dist/utils.d.ts"
}
},
"scripts": {
"build": "bun build ./src/index.ts --outdir ./dist --target bun",
"typecheck": "tsc --noEmit"
},
"peerDependencies": {
"typescript": "^5.0.0"
}
}
Internal Dependencies
// packages/backend/src/index.ts
import { validateUser, UserSchema } from "@myorg/shared";
import type { User } from "@myorg/shared/types";
const user = validateUser(data);
Running Type Checks
{
"scripts": {
"typecheck": "tsc --noEmit -p tsconfig.json",
"typecheck:all": "bun --filter '*' typecheck"
}
}
Lockfile Management
Text-based Lockfile (v1.2+)
# Migrate from binary lockfile
bun install --save-text-lockfile --frozen-lockfile --lockfile-only
rm bun.lockb
Automatic Migration
Bun automatically migrates from:
-
package-lock.json(npm) -
yarn.lock(Yarn v1) -
pnpm-lock.yaml(pnpm)
# Install and migrate lockfile
bun install
Dependency Overrides
Force specific versions for transitive dependencies:
{
"overrides": {
"lodash": "4.17.21",
"axios": "^1.6.0"
}
}
Or Yarn-style:
{
"resolutions": {
"lodash": "4.17.21"
}
}
CI/CD Integration
GitHub Actions
- uses: oven-sh/setup-bun@v1
with:
bun-version: latest
- run: bun install --frozen-lockfile
- run: bun --filter '*' typecheck
- run: bun --filter '*' build
- run: bun --filter '*' test
Docker
FROM oven/bun:1
WORKDIR /app
# Copy lockfile first for caching
COPY bun.lock package.json ./
COPY packages/*/package.json ./packages/
RUN bun install --frozen-lockfile
COPY . .
RUN bun --filter '*' build
Best Practices Summary
-
Use
private: trueon root package.json - Keep root dependencies minimal - only shared dev tools
-
Use workspace protocol (
workspace:*) for internal deps - Use catalogs for consistent versions across packages
-
Run
--frozen-lockfilein CI -
Commit
bun.lockto version control - Use glob negation to exclude test/template directories
-
Run scripts in parallel with
bun --filter '*' - Configure TypeScript paths for seamless imports
- Build dependencies first - Bun handles order automatically
When to Ask for Help
- Complex publishing workflows to npm
- Custom registry authentication
- Peer dependency conflicts
- Selective version updates in catalogs
- Integration with Turborepo or Nx
- Workspace-specific bunfig.toml overrides
chat Comments (0)
Sign in to join the discussion and leave a comment.
Skill Details
GitHub Stars
9
GitHub Forks
5
Created
Mar 2026
Last Updated
il y a 3 mois
tools
tools system admin
Related Skills
Build your own?
Join 12,000+ developers contributing to the Claude ecosystem.
No comments yet. Be the first to share your thoughts!