pnpm + Turborepo Monorepo Instructions
Claude CodeCLAUDE.mdCoding
CLAUDE.md for a pnpm/Turborepo monorepo: package boundary rules, the task pipeline, affected-only builds, and how agents should add dependencies without breaking workspaces.
Use when: Use at the root of a pnpm workspace with Turborepo so agents scope commands to the right package, respect import boundaries, and avoid running the entire pipeline for one-package changes.
Get this skill
Add the skill file with the CLI, by hand, or over MCP.Save this to your project or home directory so Claude Code can load it.
npx goodprompts add monorepo-turborepo-claude-mdSaves to
./CLAUDE.mdnpx goodprompts add monorepo-turborepo-claude-mdSaves to
./CLAUDE.mdSkill file
CLAUDE.md3,114 characters# Project Instructions — Monorepo (pnpm + Turborepo)
## Layout
```
apps/web/ # customer-facing app
apps/admin/ # internal admin app
packages/ui/ # shared React components — no app-specific code
packages/core/ # domain logic, framework-free TypeScript
packages/config/ # shared eslint/ts/tailwind config presets
```
Workspace names follow `@<your-scope>/<dir>`, e.g. `@acme/ui`. Use the workspace name, not relative paths, when importing across packages.
## Commands
Always scope to the package you changed; full-repo runs are for pre-commit verification only.
```bash
pnpm turbo run build --filter=@acme/web # build one app + its deps
pnpm turbo run test --filter=@acme/core # test one package
pnpm turbo run test --filter='...[origin/main]' # affected-only: everything changed vs main
pnpm turbo run lint typecheck test build # full pipeline — before committing
pnpm --filter @acme/web dev # dev server for one app
```
`--filter='...[origin/main]'` (changed packages plus their dependents) is the default verification for any change. Run the unfiltered pipeline only when you touched root config, `turbo.json`, or `packages/config/`.
## Dependency rules
- Add dependencies with `pnpm add <pkg> --filter @acme/<target>` — never edit a `package.json` dependencies block by hand, and never `pnpm add` at the root unless it is a repo-wide dev tool.
- Internal dependencies use `"workspace:*"`. If you import from a sibling package, you must add it to that package's `package.json`; pnpm's strict node linker will fail otherwise — that failure is correct, do not work around it with root installs.
- Allowed import directions: `apps/* → packages/*`, `packages/ui → packages/core`. Never `packages/* → apps/*`, and never between the two apps. If two apps need the same code, move it into a package.
## Pipeline (turbo.json)
- `build` depends on `^build` (upstream packages build first). `test` and `typecheck` depend on `^build`.
- Outputs are cached. If a task seems stale, run with `--force` once to confirm before suspecting the cache; do not delete `.turbo/` as a first resort.
- When you add a task to a package, register it in `turbo.json` with correct `dependsOn` and `outputs`, otherwise caching will silently misbehave.
## Conventions
- Each package owns its `tsconfig.json`, extending `@acme/config/tsconfig.base.json`. Do not duplicate compiler options that the base already sets.
- Shared packages export through an explicit `exports` map in `package.json` — no deep imports like `@acme/core/src/internal/foo`.
- Changes that touch a shared package require running tests for its dependents: `pnpm turbo run test --filter='...@acme/core'` (note the leading `...` selects dependents).
- Generated files (`dist/`, `.turbo/`, `*.tsbuildinfo`) are never edited or committed.
## Gotchas
- Node version is pinned in `.nvmrc` and `engines`; pnpm version in `packageManager`. Do not bump either casually.
- `pnpm-lock.yaml` conflicts: take main's version, then re-run `pnpm install` — never hand-merge the lockfile.