| name | workspace-management |
| description | Manage pnpm workspaces, add packages, configure dependencies, and organize monorepo structure. Use when adding new packages, restructuring workspace, or managing cross-package dependencies. |
| allowed-tools | Read, Edit, Write, Bash, Grep, Glob |
Workspace Management Skill
This skill helps you manage the pnpm monorepo workspace structure and dependencies.
When to Use This Skill
- Adding new packages to monorepo
- Configuring workspace dependencies
- Managing cross-package dependencies
- Restructuring workspace
- Sharing code between packages
- Setting up new apps or packages
- Managing workspace scripts
Workspace Structure
sgcarstrends/
├── pnpm-workspace.yaml # Workspace configuration
├── package.json # Root package.json
├── turbo.json # Turbo configuration
├── apps/
│ ├── api/ # API service
│ ├── web/ # Web application
│ ├── admin/ # Admin panel
│ └── docs/ # Documentation
├── packages/
│ ├── database/ # Database schemas
│ ├── types/ # Shared types
│ ├── ui/ # UI components
│ ├── utils/ # Utilities
│ └── logos/ # Logo management
└── infra/ # Infrastructure
Workspace Configuration
pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
- "infra"
catalog:
# React ecosystem
next: ^16.0.0
react: ^19.0.0
react-dom: ^19.0.0
# Database
drizzle-orm: ^0.30.0
drizzle-kit: ^0.20.0
postgres: ^3.4.3
# TypeScript
typescript: ^5.3.3
"@types/node": ^20.11.5
"@types/react": ^19.0.0
# Build tools
"@biomejs/biome": ^1.9.4
turbo: ^2.3.3
# Testing
vitest: ^2.1.8
"@playwright/test": ^1.49.1
Adding New Package
Create Package Structure
# Create package directory
mkdir -p packages/new-package/src
# Create package.json
cat > packages/new-package/package.json <<EOF
{
"name": "@sgcarstrends/new-package",
"version": "1.0.0",
"type": "module",
"exports": {
".": {
"types": "./src/index.ts",
"default": "./src/index.ts"
}
},
"scripts": {
"test": "vitest run",
"test:watch": "vitest",
"typecheck": "tsc --noEmit"
},
"dependencies": {},
"devDependencies": {
"typescript": "catalog:",
"vitest": "catalog:"
}
}
EOF
Create TypeScript Config
// packages/new-package/tsconfig.json
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "./src"
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "__tests__"]
}
Create Entry Point
// packages/new-package/src/index.ts
export { myFunction } from "./my-function";
Install Dependencies
# Install workspace dependencies
pnpm install
# Install package-specific dependency
pnpm -F @sgcarstrends/new-package add some-package
Managing Dependencies
Add Dependency to Package
# Add to specific package
pnpm -F @sgcarstrends/api add hono
# Add dev dependency
pnpm -F @sgcarstrends/web add -D tailwindcss
# Add from catalog
pnpm -F @sgcarstrends/web add typescript # Automatically uses catalog:
Add Workspace Dependency
# Add internal dependency
pnpm -F @sgcarstrends/web add @sgcarstrends/database
# package.json will have:
{
"dependencies": {
"@sgcarstrends/database": "workspace:*"
}
}
Add Dependency to All Packages
# Add to root (CLI tools)
pnpm add -w -D biome turbo
# Add to all workspaces
pnpm -r add some-package
Remove Dependency
# Remove from specific package
pnpm -F @sgcarstrends/api remove lodash
# Remove from all packages
pnpm -r remove lodash
# Remove from root
pnpm remove -w lodash
Cross-Package Dependencies
Import from Workspace Package
// apps/web/src/app/page.tsx
import { db } from "@sgcarstrends/database";
import { redis } from "@sgcarstrends/utils";
import { Button } from "@sgcarstrends/ui/components/button";
export default async function Page() {
const cars = await db.query.cars.findMany();
return <div>...</div>;
}
TypeScript Path Mapping
// tsconfig.json (root)
{
"compilerOptions": {
"paths": {
"@sgcarstrends/database": ["./packages/database/src"],
"@sgcarstrends/types": ["./packages/types/src"],
"@sgcarstrends/ui": ["./packages/ui/src"],
"@sgcarstrends/utils": ["./packages/utils/src"]
}
}
}
Workspace Scripts
Root package.json Scripts
{
"scripts": {
// Development
"dev": "turbo dev",
"dev:api": "pnpm -F @sgcarstrends/api dev",
"dev:web": "pnpm -F @sgcarstrends/web dev",
// Build
"build": "turbo build",
"build:api": "pnpm -F @sgcarstrends/api build",
"build:web": "pnpm -F @sgcarstrends/web build",
// Testing
"test": "turbo test",
"test:watch": "turbo test:watch",
"test:coverage": "turbo test:coverage",
// Linting
"lint": "biome check .",
"lint:fix": "biome check --write .",
// Database
"db:generate": "pnpm -F @sgcarstrends/database db:generate",
"db:migrate": "pnpm -F @sgcarstrends/database db:migrate",
"db:push": "pnpm -F @sgcarstrends/database db:push",
// Deployment
"deploy:dev": "turbo deploy:dev",
"deploy:staging": "turbo deploy:staging",
"deploy:prod": "turbo deploy:prod"
}
}
Package-Specific Scripts
// apps/api/package.json
{
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "esbuild src/index.ts --bundle --platform=node --outfile=dist/index.js",
"test": "vitest run",
"test:watch": "vitest",
"deploy:dev": "sst deploy --stage dev",
"deploy:staging": "sst deploy --stage staging",
"deploy:prod": "sst deploy --stage prod"
}
}
Turbo Configuration
turbo.json
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"test": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"]
},
"test:watch": {
"cache": false,
"persistent": true
},
"lint": {
"outputs": []
},
"deploy:dev": {
"dependsOn": ["build"],
"cache": false
},
"deploy:staging": {
"dependsOn": ["build", "test"],
"cache": false
},
"deploy:prod": {
"dependsOn": ["build", "test", "lint"],
"cache": false
}
}
}
Common Operations
List All Packages
# List workspace packages
pnpm list --depth 0
# List recursively
pnpm -r list
# List specific package
pnpm -F @sgcarstrends/api list
Run Commands in Parallel
# Run dev in all packages
pnpm -r dev
# Build all packages
pnpm -r build
# Test all packages
pnpm -r test
Filter by Package
# Run command in specific package
pnpm -F @sgcarstrends/api dev
# Run in multiple packages
pnpm -F @sgcarstrends/api -F @sgcarstrends/web build
# Run in all packages matching pattern
pnpm -F "@sgcarstrends/*" build
Execute Script in All Packages
# Clean all packages
pnpm -r exec rm -rf node_modules dist .turbo .next
# Update all package versions
pnpm -r exec npm version patch
Workspace Optimization
Hoisting
# .npmrc
hoist=true
hoist-pattern[]=*
shamefully-hoist=false
Shared Dependencies
# pnpm-workspace.yaml
catalog:
# Shared across all packages
typescript: ^5.3.3
vitest: ^2.1.8
biome: ^1.9.4
# package.json uses:
{
"devDependencies": {
"typescript": "catalog:",
"vitest": "catalog:",
"biome": "catalog:"
}
}
Node Modules Structure
node_modules/
├── .pnpm/ # Virtual store
│ ├── next@16.0.0/
│ ├── react@19.0.0/
│ └── ...
├── @sgcarstrends/
│ ├── database -> ../packages/database
│ ├── types -> ../packages/types
│ └── ...
└── next -> .pnpm/next@16.0.0/node_modules/next
Package Publishing
Prepare for Publishing
// packages/ui/package.json
{
"name": "@sgcarstrends/ui",
"version": "1.0.0",
"type": "module",
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./components/*": {
"types": "./dist/components/*.d.ts",
"default": "./dist/components/*.js"
}
},
"files": [
"dist",
"README.md",
"LICENSE"
],
"scripts": {
"build": "tsc",
"prepublishOnly": "pnpm build"
},
"publishConfig": {
"access": "public"
}
}
Publish Package
# Build package
pnpm -F @sgcarstrends/ui build
# Publish to npm
pnpm -F @sgcarstrends/ui publish
# Publish all changed packages
pnpm -r publish
Troubleshooting
Dependency Not Found
# Issue: Module not found @sgcarstrends/database
# Solution: Rebuild workspace
pnpm install
# Or rebuild specific package
pnpm -F @sgcarstrends/database build
Circular Dependencies
# Issue: Circular dependency detected
# Solution: Refactor to break circle
# Bad:
# A depends on B
# B depends on A
# Good:
# A depends on C
# B depends on C
# C has shared code
Hoisting Issues
# Issue: Package not found due to hoisting
# Solution: Add to .npmrc
# .npmrc
public-hoist-pattern[]=*react*
public-hoist-pattern[]=*next*
Workspace Protocol Issues
# Issue: workspace:* not resolving
# Solution: Ensure package exists and is built
pnpm -F @sgcarstrends/database build
pnpm install
Best Practices
1. Organize by Type
# ✅ Good organization
apps/ # User-facing applications
packages/ # Shared libraries
infra/ # Infrastructure code
# ❌ Poor organization
src/ # Mixed apps and packages
lib/ # Unclear purpose
2. Use Catalog for Shared Versions
# ✅ Centralized versions
catalog:
react: ^19.0.0
typescript: ^5.3.3
# ❌ Duplicate versions
# Each package.json has different versions
3. Minimize Cross-Dependencies
// ❌ Deep cross-dependencies
// web → api → database → types → utils → config
// ✅ Flat dependencies
// web → database, types, utils
// api → database, types, utils
4. Document Package Purpose
# packages/ui/README.md
# @sgcarstrends/ui
Shared UI component library built with shadcn/ui and Tailwind CSS.
## When to Use
Use this package when you need to share UI components between web and admin apps.
## Examples
\```typescript
import { Button } from "@sgcarstrends/ui/components/button";
\```
References
- pnpm Workspaces: https://pnpm.io/workspaces
- Turbo: https://turbo.build/repo/docs
- Monorepo Tools: https://monorepo.tools
- Related files:
pnpm-workspace.yaml- Workspace configurationturbo.json- Turbo configuration- Root CLAUDE.md - Workspace guidelines
Best Practices Summary
- Clear Structure: Organize packages by type (apps, packages, infra)
- Use Catalog: Centralize dependency versions
- Workspace Protocol: Use
workspace:*for internal dependencies - Turbo Pipeline: Configure build dependencies correctly
- Minimal Cross-Deps: Avoid deep dependency chains
- Document Packages: Clear README for each package
- Consistent Scripts: Use same script names across packages
- Optimize Hoisting: Configure hoisting for performance