Monorepos (Turborepo / Nx / pnpm workspaces)

One repo for multiple packages. Useful when they evolve together; painful when they shouldn't.

1 credit

Why bother

  • Shared code (UI kit, utils) without publishing to npm.
  • Atomic changes across apps + libs in one PR.
  • Unified lint / typecheck / test config.
  • Dependency graph enables smart caching — only rebuild what changed.

The players

5 items
pnpm workspaces
Just a package manager feature. Free, minimal. Start here.
npm / yarn workspaces
Same idea, worse hoisting. pnpm is strictly better.
Turborepo
Task runner + remote cache. Zero config to add. Great for Vercel-hosted.
Nx
More opinionated. Graph, generators, cloud cache. Heavier but more features.
Bazel / Buck
Monorepos at Google/FB scale. Massive setup cost. Not for teams <50.

Minimal pnpm workspace

text
# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

# Folder layout
apps/
  web/           # Next.js app
  docs/          # another app
packages/
  ui/            # shared UI components
  utils/         # shared helpers

# In apps/web/package.json
"dependencies": { "@acme/ui": "workspace:*" }

Gotchas

  • Package boundaries matter — circular deps between packages are allowed by bundlers but cause headaches later.
  • Version skew — if `@acme/ui` needs React 19 and `apps/web` pins 18, you'll see duplicated React in node_modules.
  • CI cost explodes without caching — rebuilding every package on every push is slow. Use Turbo/Nx remote cache.
  • Don't monorepo things that shouldn't move together. Independent release cycles → separate repos.

Further reading