/library / template-monorepo-turborepo
templateTooling

Monorepo with pnpm workspaces + Turborepo (Next + Express + shared UI)

A monorepo for teams running 2+ deployables (web app, marketing site, API, shared UI library, design tokens). pnpm workspaces, Turborepo for caching, changesets for versioning. Build the right packages, deploy the right apps, only when needed.

use whenYour team is shipping multiple apps sharing code (auth, UI, types). You're tired of copy-paste-modify between repos and ready to invest a day in monorepo infrastructure.

April 26, 20262,090 bytesmonorepoturborepopnpmworkspaceschangesets

[Org Name] · Monorepo

A pnpm + Turborepo monorepo. Apps in apps/, shared packages in packages/. Turborepo handles caching + parallel builds.

Source of truth

The monorepo is the source. Apps are independently deployable (Vercel, Fly, etc) but share code through packages/*. Versions of internal packages are managed by changesets.

Tech stack

pnpm 10 + Turborepo 2 + TypeScript 5.6+ + Vitest (workspace-aware). ESLint + Prettier (shared configs). Changesets for versioning internal packages (and any published-to-npm ones). Per-app deploy targets: Vercel for Next apps, Fly for Express API.

Deploy

Each app deploys independently. CI uses Turborepo remote cache for fast builds across PRs and across apps.

File map

  • apps/web/ Next.js marketing site
  • apps/app/ Next.js application
  • apps/api/ Node Express API
  • packages/ui/ shared React components + Tailwind preset
  • packages/db/ Drizzle schema + queries (shared by api + app)
  • packages/auth/ JWT + session helpers
  • packages/config/ shared TS, ESLint, Tailwind configs
  • packages/utils/ shared utility functions
  • pnpm-workspace.yaml workspace globs
  • turbo.json task pipeline + cache config
  • .changeset/ changesets per change

.env keys

Per-app .env.local files. Root .env.example shows the union of all needed vars.

Hard rules

  • Internal packages use workspace:* in dependents' package.json. NEVER hardcode version numbers for internal deps.
  • Every package has a package.json exports field. No deep imports across packages.
  • turbo.json task pipeline mirrors actual dependency order. build depends on ^build (upstream builds first).
  • TypeScript paths configured per-package, NOT globally. Each app's tsconfig extends packages/config/tsconfig.base.json.
  • Changesets for any internal-package change. CI runs changeset version on merge to bump packages atomically.
  • Lockfile is committed (pnpm-lock.yaml). Frozen lockfile in CI (pnpm install --frozen-lockfile).

Recent significant changes

  • 2026-04-26: Scaffolded. Locked: pnpm over yarn/npm (faster, stricter), Turborepo over Nx (less ceremony), changesets over standard-version (multi-package monorepos demand it).

Next session: start here

  1. pnpm install from root. Confirm all workspaces resolve.
  2. Run pnpm turbo build to warm the cache. Time the second run (should be near-instant).
  3. Move shared code into packages/. Start with one piece (auth helpers, UI button).
  4. Set up Turborepo remote cache (Vercel or Cloudflare). Confirm CI uses it.
  5. Configure each app's deploy target. Vercel auto-detects monorepo apps; point each to its apps/* directory.

Get the next CLAUDE.md in your inbox.

One new template every week, plus occasional case studies.