Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Configure and optimize Turborepo monorepo build pipelines with correct task structure, caching, and CI setup.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
references/best-practices/RULE.md
1# Monorepo Best Practices23Essential patterns for structuring and maintaining a healthy Turborepo monorepo.45## Repository Structure67### Standard Layout89```10my-monorepo/11├── apps/ # Application packages (deployable)12│ ├── web/13│ ├── docs/14│ └── api/15├── packages/ # Library packages (shared code)16│ ├── ui/17│ ├── utils/18│ └── config-*/ # Shared configs (eslint, typescript, etc.)19├── package.json # Root package.json (minimal deps)20├── turbo.json # Turborepo configuration21├── pnpm-workspace.yaml # (pnpm) or workspaces in package.json22└── pnpm-lock.yaml # Lockfile (required)23```2425### Key Principles26271. **`apps/` for deployables**: Next.js sites, APIs, CLIs - things that get deployed282. **`packages/` for libraries**: Shared code consumed by apps or other packages293. **One purpose per package**: Each package should do one thing well304. **No nested packages**: Don't put packages inside packages3132## Package Types3334### Application Packages (`apps/`)3536- **Deployable**: These are the "endpoints" of your package graph37- **Not installed by other packages**: Apps shouldn't be dependencies of other packages38- **No shared code**: If code needs sharing, extract to `packages/`3940```json41// apps/web/package.json42{43"name": "web",44"private": true,45"dependencies": {46"@repo/ui": "workspace:*",47"next": "latest"48}49}50```5152### Library Packages (`packages/`)5354- **Shared code**: Utilities, components, configs55- **Namespaced names**: Use `@repo/` or `@yourorg/` prefix56- **Clear exports**: Define what the package exposes5758```json59// packages/ui/package.json60{61"name": "@repo/ui",62"exports": {63"./button": "./src/button.tsx",64"./card": "./src/card.tsx"65}66}67```6869## Package Compilation Strategies7071### Just-in-Time (Simplest)7273Export TypeScript directly; let the app's bundler compile it.7475```json76{77"name": "@repo/ui",78"exports": {79"./button": "./src/button.tsx"80}81}82```8384**Pros**: Zero build config, instant changes85**Cons**: Can't cache builds, requires app bundler support8687### Compiled (Recommended for Libraries)8889Package compiles itself with `tsc` or bundler.9091```json92{93"name": "@repo/ui",94"exports": {95"./button": {96"types": "./src/button.tsx",97"default": "./dist/button.js"98}99},100"scripts": {101"build": "tsc"102}103}104```105106**Pros**: Cacheable by Turborepo, works everywhere107**Cons**: More configuration108109## Dependency Management110111### Install Where Used112113Install dependencies in the package that uses them, not the root.114115```bash116# Good: Install in the package that needs it117pnpm add lodash --filter=@repo/utils118119# Avoid: Installing everything at root120pnpm add lodash -w # Only for repo-level tools121```122123### Root Dependencies124125Only these belong in root `package.json`:126127- `turbo` - The build system128- `husky`, `lint-staged` - Git hooks129- Repository-level tooling130131### Internal Dependencies132133Use workspace protocol for internal packages:134135```json136// pnpm/bun137{ "@repo/ui": "workspace:*" }138139// npm/yarn140{ "@repo/ui": "*" }141```142143## Exports Best Practices144145### Use `exports` Field (Not `main`)146147```json148{149"exports": {150".": "./src/index.ts",151"./button": "./src/button.tsx",152"./utils": "./src/utils.ts"153}154}155```156157### Avoid Barrel Files158159Don't create `index.ts` files that re-export everything:160161```typescript162// BAD: packages/ui/src/index.ts163export * from './button';164export * from './card';165export * from './modal';166// ... imports everything even if you need one thing167168// GOOD: Direct exports in package.json169{170"exports": {171"./button": "./src/button.tsx",172"./card": "./src/card.tsx"173}174}175```176177### Namespace Your Packages178179```json180// Good181{ "name": "@repo/ui" }182{ "name": "@acme/utils" }183184// Avoid (conflicts with npm registry)185{ "name": "ui" }186{ "name": "utils" }187```188189## Common Anti-Patterns190191### Accessing Files Across Package Boundaries192193```typescript194// BAD: Reaching into another package195import { Button } from "../../packages/ui/src/button";196197// GOOD: Install and import properly198import { Button } from "@repo/ui/button";199```200201### Shared Code in Apps202203```204// BAD205apps/206web/207shared/ # This should be a package!208utils.ts209210// GOOD211packages/212utils/ # Proper shared package213src/utils.ts214```215216### Too Many Root Dependencies217218```json219// BAD: Root has app dependencies220{221"dependencies": {222"react": "^18",223"next": "^14",224"lodash": "^4"225}226}227228// GOOD: Root only has repo tools229{230"devDependencies": {231"turbo": "latest",232"husky": "latest"233}234}235```236237## See Also238239- [structure.md](./structure.md) - Detailed repository structure patterns240- [packages.md](./packages.md) - Creating and managing internal packages241- [dependencies.md](./dependencies.md) - Dependency management strategies242