TypeScript Monorepo (Turborepo)
Turborepo + pnpm workspaces: shared types, build pipelines, caching.
# CLAUDE.md — TypeScript Monorepo (Turborepo)
## Layout
```
apps/
web/ # the Next.js / React / etc. app
api/ # backend
marketing/
packages/
ui/ # shared React components
config/ # tsconfig, eslint, prettier presets
utils/ # framework-agnostic utilities
types/ # shared type definitions
turbo.json
package.json # workspaces root
pnpm-workspace.yaml # if pnpm
```
- `apps/*` are deployable. `packages/*` are internal libraries.
- Each package has its own `package.json`, `tsconfig.json`, build scripts.
## Package manager
- **pnpm** is the default. It saves disk and enforces strict dep boundaries.
- `pnpm-workspace.yaml`:
```yaml
packages:
- "apps/*"
- "packages/*"
```
- Add `"workspace:*"` for internal package versions in dependent `package.json`s.
## TypeScript config
- One base `tsconfig.json` in `packages/config/typescript`. Apps and packages extend it:
```json
{ "extends": "@repo/config/typescript/base.json", "include": ["src"] }
```
- Use **TypeScript project references** for incremental builds across packages. `tsc --build` walks the graph.
- Each package emits to its own `dist/`. Source-only consumers read from `src/` via the `exports` map.
## Turbo pipelines
- `turbo.json` declares task dependencies, inputs, outputs, and cache rules:
```json
{
"tasks": {
"build": { "dependsOn": ["^build"], "outputs": ["dist/**"] },
"lint": { "dependsOn": ["^build"] },
"test": { "dependsOn": ["^build"], "outputs": ["coverage/**"] }
}
}
```
- `^build` means "build my dependencies first." Get this right and CI flies.
- Outputs are what's cacheable. Inputs default to all package files; narrow them when relevant.
## Caching
- Local cache by default. **Remote cache** for CI: `turbo login` + `turbo link`, or self-hosted.
- Cache misses on `node_modules` mean your `inputs` are too broad.
- Don't cache flaky tests. Mark them `cache: false`.
## Internal package consumption
- Use `workspace:*` everywhere — never relative paths into other packages.
- Re-export the public surface from `package.json#exports`. Don't let consumers reach into `dist/internal/`.
- For server-only code, mark with `"type": "module"` or split into separate sub-paths.
## Linting & formatting
- One ESLint config in `packages/config/eslint/`. Apps extend it.
- Ban cross-package imports that aren't declared as deps via `eslint-plugin-import`.
- One Prettier config at the root. Don't fork per package.
## Don't
- Don't put deployable apps inside `packages/` or libraries inside `apps/`.
- Don't share devDependencies via the root `package.json` — each package declares what it actually uses.
- Don't `tsc` from the root and pretend it's a build. Use Turbo's `build` task or it won't cache.
- Don't depend on a package's internal files (`@repo/ui/dist/internal/x`). Always go through `exports`.
Other TypeScript templates
Next.js App Router + TypeScript Rules
Server Components, Server Actions, and TypeScript discipline for the Next.js App Router.
Next.js + Server Actions + Shadcn UI
Forms with Server Actions, Zod validation, and Shadcn UI primitives.
Next.js + Supabase Auth
Auth flows with Supabase SSR, cookies, and Row Level Security policies.
Next.js + Tailwind + Prisma Stack
Full-stack Next.js with Prisma ORM, Tailwind CSS, and Postgres.
Next.js SEO + Metadata Rules
Metadata API, sitemap, robots, OG images, and structured data done right.