Monorepo with Turborepo: The Practical Guide for TypeScript Teams
Turborepo adds intelligent caching and parallel task execution to TypeScript monorepos. Here's a complete setup guide and an honest look at where it shines and where it struggles.
Turborepo is the right choice for managing a TypeScript monorepo when your repo has 2 to 10 packages and your team wants fast builds without a dedicated platform engineering team. It adds two things to a standard pnpm or npm workspaces setup: intelligent task caching (only rebuild what changed) and parallel task execution (run builds and tests across packages at the same time). Below that scale, workspaces alone are sufficient. Above 10 packages, Turborepo still works but Nx or Bazel may be worth evaluating.
Why Monorepos at All
Before the tooling, the reason. A monorepo puts multiple related packages in one git repository. For a TypeScript product, that might be:
packages/ui - shared React components
packages/types - shared TypeScript interfaces
packages/utils - shared utility functions
apps/web - Next.js web app
apps/admin - internal admin panel
apps/api - Express or Fastify API server
The alternative is separate repositories for each of these, with npm publish/install cycles between them. The monorepo eliminates that cycle: packages/ui changes are immediately available in apps/web without publishing. You can make an atomic commit that changes a type in packages/types and updates every app that uses it simultaneously.
The cost: build systems need to understand package dependencies to only rebuild what changed. Without tooling, a monorepo's build script re-runs everything, every time.
What Turborepo Adds
Intelligent caching. Turborepo hashes the inputs to each task (source files, environment variables, dependencies) and caches the output. On the next run, if nothing changed, it restores from cache instead of rebuilding. This makes subsequent builds near-instant for unchanged packages.
Parallel task execution. Turborepo reads your package dependency graph and runs tasks in parallel when safe. If apps/web depends on packages/ui, Turborepo builds packages/ui first, then starts apps/web as soon as packages/ui finishes - while simultaneously building packages/admin if it has different dependencies.
Remote cache. Share the task cache across your team (and CI) via Vercel or a self-hosted cache server. When a colleague builds the same packages with the same inputs, you get their cached output. CI runs hit the cache instead of rebuilding from scratch.
// stay current
AI & ML insights, weekly
Practical deep-dives on LLMs, developer tools, and AI engineering. No filler. Unsubscribe any time.
// written byFIG. AUTH-01
530
Mahmudul Haque Qudrati
CEO & ML Engineer
CEO and ML Engineer at Pristren. Builds AI-powered software for teams and writes about machine learning, LLMs, developer tools, and practical AI applications.
The "^build" syntax means "run build in all dependencies first." So if apps/web depends on packages/ui, Turborepo automatically builds packages/ui before apps/web.
Step 4: Add workspace root scripts to package.json.
Run pnpm install at the root and pnpm creates symlinks between packages.
Running Tasks
# Build everything, in dependency order, with caching
pnpm turbo build
# Build only the web app and its dependencies
pnpm turbo build --filter=web
# Build all apps (not packages)
pnpm turbo build --filter="./apps/*"
# Run dev servers for all apps
pnpm turbo dev
# Run dev server for just the web app
pnpm turbo dev --filter=web
The --filter flag is essential for large monorepos where you only want to work on one app at a time.
Remote Caching with Vercel
Vercel provides a free remote cache for Turborepo. Set it up:
npx turbo login
npx turbo link
After linking, every turbo build run uploads its output to Vercel's cache. On CI, the same build gets restored from cache. For teams of 2-5 developers, this can reduce CI build times from 5 minutes to under 30 seconds for unchanged code.
Self-hosted remote cache: If you don't want to use Vercel, ducktape and turborepo-remote-cache are open source implementations. Configure in turbo.json:
Turborepo is excellent for 2-10 package repos. The setup is straightforward, the caching works reliably, and the performance gains on repeat builds are substantial.
Above 10 packages, cracks appear. The --filter syntax becomes essential but also more complex. Task pipeline debugging gets harder. Teams that grow past ~20 packages often evaluate Nx, which has more sophisticated dependency graph tooling and better workspace generators.
The other limitation: Turborepo is purely a build orchestration tool. It doesn't help with shared ESLint configuration, TypeScript project references, shared testing setup, or changelogs. You'll build those patterns separately. Nx provides more of an opinionated full-stack monorepo solution, at the cost of more complexity upfront.
For most teams building a Next.js app with shared components and types, Turborepo is the right amount of tooling.
Best Practices for TypeScript Monorepos with Turborepo
Use TypeScript project references to enable incremental builds. Configure each package's tsconfig.json with composite: true and reference them in the root tsconfig.json. Turborepo's caching works alongside this, but project references give you faster type-checking in editors.
Keep turbo.json minimal. Only define tasks that need special pipeline rules. For simple scripts like lint, you can omit dependsOn and outputs — Turborepo will still cache them based on file hashes.
Use --filter aggressively. When working on a single app, always filter to avoid building unrelated packages. This keeps dev loop fast.
Set up remote caching early. Even for a solo developer, remote cache helps when switching branches or machines. For teams, it's essential to avoid redundant CI builds.
Version your packages with changesets. Turborepo doesn't handle versioning. Use @changesets/cli to manage changelogs and publish versions for packages that are published to npm.
Common Pitfalls and How to Avoid Them
Missing outputs in turbo.json: If you don't specify outputs, Turborepo won't cache the build artifacts. Always list the output directories (e.g., dist/**, .next/**).
Incorrect dependsOn: The ^ prefix means "dependencies' tasks." Forgetting it can cause out-of-order builds. Double-check your pipeline.
Environment variable mismatches: Turborepo hashes environment variables. If CI has different env vars than local, cache misses occur. Use globalDependencies in turbo.json to include env vars that affect all tasks.
Circular dependencies: Turborepo will error if packages have circular dependencies. Keep your dependency graph acyclic.
Pristren builds AI-powered software for teams. Zlyqor is our all-in-one workspace - chat, projects, time tracking, AI meeting summaries, and invoicing - in one tool. Try it free.
Frequently Asked Questions
What is a monorepo with Turborepo for TypeScript teams?
A monorepo with Turborepo is a single Git repository containing multiple TypeScript packages (e.g., shared UI components, types, utilities, and apps like Next.js or Express). Turborepo adds intelligent caching and parallel task execution on top of pnpm or npm workspaces, so only changed packages are rebuilt and tasks run in dependency order.
How does Turborepo work in a TypeScript monorepo?
Turborepo reads a `turbo.json` pipeline configuration that defines tasks (build, test, lint) and their dependencies. It hashes inputs (source files, env vars, dependencies) and caches outputs. On subsequent runs, if inputs haven't changed, it restores from cache instead of re-executing. It also runs independent tasks in parallel, respecting the dependency graph.
What are the best practices for setting up a Turborepo monorepo?
Best practices include: using TypeScript project references for incremental type-checking, keeping `turbo.json` minimal with only necessary pipeline rules, using `--filter` to limit builds to specific apps, setting up remote caching early (via Vercel or self-hosted), and using changesets for versioning. Also ensure `outputs` are correctly specified to enable caching.
How much does Turborepo cost?
Turborepo itself is open-source and free. The remote caching service from Vercel has a free tier (up to 5 users, 6 GB cache) and paid plans for larger teams. Self-hosted remote cache alternatives like `ducktape` are also free. There are no licensing costs for using Turborepo.
Is Turborepo worth it in 2026?
Yes, for TypeScript teams with 2–10 packages, Turborepo remains a solid choice in 2026. It's lightweight, easy to set up, and significantly speeds up builds via caching. However, for larger monorepos (20+ packages), Nx or Bazel may offer better scalability and tooling. Turborepo's simplicity is its strength for small to medium projects.
What are the alternatives to Turborepo for TypeScript monorepos?
Alternatives include Nx (more feature-rich, with generators and dependency graph visualization), Bazel (highly scalable but complex), and Lerna (less actively maintained). For very small projects, plain pnpm workspaces may suffice without a build orchestrator.
Can Turborepo work with npm or yarn workspaces?
Yes, Turborepo works with npm, yarn, and pnpm workspaces. The setup is similar: define workspaces in `package.json` or `pnpm-workspace.yaml`, install Turborepo, and configure `turbo.json`. pnpm is recommended for its strict dependency resolution and speed.