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 componentspackages/types— shared TypeScript interfacespackages/utils— shared utility functionsapps/web— Next.js web appapps/admin— internal admin panelapps/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.
Setup Walkthrough
Step 1: Create the workspace structure.
mkdir my-monorepo
cd my-monorepo
pnpm init
Create pnpm-workspace.yaml:
packages:
- "apps/*"
- "packages/*"
Create the directory structure:
mkdir -p apps/web apps/admin packages/ui packages/types packages/utils
Step 2: Install Turborepo.
pnpm add turbo --save-dev -w
The -w flag installs at the workspace root.
Step 3: Create turbo.json.
This is Turborepo's pipeline configuration:
{
"$schema": "https://turborepo.org/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**", "build/**"]
},
"test": {
"dependsOn": ["^build"],
"outputs": []
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
}
}
}
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.
{
"scripts": {
"build": "turbo build",
"test": "turbo test",
"lint": "turbo lint",
"dev": "turbo dev"
}
}
Step 5: Configure each package.
Each package needs a package.json with a name, version, and the same script names:
{
"name": "@myapp/ui",
"version": "0.0.1",
"scripts": {
"build": "tsc --outDir dist",
"lint": "eslint ."
}
}
Step 6: Define inter-package dependencies.
In apps/web/package.json, reference the local package:
{
"dependencies": {
"@myapp/ui": "workspace:*",
"@myapp/types": "workspace:*"
}
}
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:
{
"remoteCache": {
"apiUrl": "https://your-cache-server.com"
}
}
Realistic Assessment
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.
Keep Reading
- CI/CD for Small Engineering Teams — How Turborepo's remote cache integrates with GitHub Actions
- Docker for Developers Guide — Containerizing a monorepo for consistent builds
- We Replaced 6 SaaS Tools with One: What Happened — How Pristren manages its monorepo in production
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.