Claude Code for Bun Workspaces — Workflow Guide
The Setup
You are managing a monorepo using Bun’s built-in workspace support. Unlike npm or pnpm workspaces that need separate tools for linking and building, Bun handles workspaces natively with zero-config linking and fast installs. Claude Code can scaffold workspace packages and manage cross-dependencies, but it defaults to npm/yarn workspace patterns that conflict with Bun’s approach.
What Claude Code Gets Wrong By Default
-
Adds lerna, turbo, or nx for workspace management. Claude installs monorepo tools on top of Bun. Bun workspaces handle dependency linking natively —
bun installat the root links all packages automatically. -
Uses
npm linkoryarn linkfor local packages. Claude runs manual linking commands. Bun resolves workspace packages through the"workspaces"field in rootpackage.jsonwithout any link step. -
Creates
.npmrcor.yarnrcfiles. Claude generates package manager config files for the wrong runtime. Bun readsbunfig.tomlfor configuration, not npm or yarn config files. -
Writes CommonJS in workspace packages. Claude defaults to
module.exports. Bun workspaces work best with ESM — use"type": "module"in each package’spackage.jsonandexportsyntax in source files.
The CLAUDE.md Configuration
# Bun Monorepo with Workspaces
## Architecture
- Runtime: Bun
- Monorepo: Bun native workspaces
- Structure: packages/* and apps/* directories
- Config: bunfig.toml for Bun settings, NOT .npmrc
## Workspace Rules
- Root package.json has "workspaces": ["packages/*", "apps/*"]
- Run bun install at root only — links all packages automatically
- Reference workspace packages by name: "my-lib": "workspace:*"
- No lerna, no turbo, no nx — Bun handles it natively
- Scripts run from root: bun run --filter my-app dev
- Each package has its own package.json with "type": "module"
## Conventions
- Shared packages in packages/ directory
- Applications in apps/ directory
- Package names prefixed: @myorg/package-name
- Each package exports via package.json "exports" field
- TypeScript: each package has own tsconfig extending root
- Test with bun test (built-in test runner, no Jest needed)
- Never use require() — ESM imports only
Workflow Example
You want to create a shared UI component package used by two apps. Prompt Claude Code:
“Create a new workspace package called @myorg/ui in packages/ui with a Button component. Add it as a dependency to apps/web and apps/docs. Make sure TypeScript types are exported correctly.”
Claude Code should create packages/ui/package.json with proper "exports" and "types" fields, write the Button component with TypeScript, add "@myorg/ui": "workspace:*" to both apps’ package.json files, and run bun install at the root to link everything.
Common Pitfalls
-
Forgetting
workspace:*protocol. Claude adds dependencies with version numbers like"@myorg/ui": "^1.0.0". Bun workspaces require theworkspace:*protocol to resolve local packages instead of looking them up in the npm registry. -
Running
bun installin individual packages. Claude runs install in each package directory separately. With Bun workspaces, always runbun installfrom the monorepo root — it handles all packages at once and creates the correct symlinks. -
TypeScript path mapping conflicts. Claude adds
pathsintsconfig.jsonto resolve workspace packages. Bun’s workspace linking makes packages available by name already. Adding redundant path mappings causes resolution conflicts when both Bun and TypeScript try to resolve the same import.