Last updated on 12th August 2026

Turborepo: Faster Monorepo Builds and Deployments

As a codebase grows into a monorepo — several apps and shared packages in one repository — builds get slow. Rebuilding everything on every change wastes minutes you don't have, especially in a deployment pipeline. Turborepo fixes that by understanding the dependency graph between your packages, running tasks in parallel, and caching results so nothing is ever built twice unnecessarily. This guide covers setting up Turborepo and deploying a monorepo app with DeployHQ.

What Turborepo does

Turborepo is a build orchestrator for JavaScript and TypeScript monorepos. It doesn't replace your bundler or test runner — it coordinates them. Given a set of tasks (build, test, lint) across many packages, it figures out the correct order from your dependency graph, runs independent work in parallel, and caches each task's output. Change one package and Turborepo rebuilds only that package and the things that depend on it; everything else is restored from cache instantly.

It sits on top of your existing workspace setup — npm, Yarn, or pnpm workspaces — and adds the orchestration layer.

Setting up a workspace

Turborepo works with any workspace manager. pnpm workspaces are a common pairing; you declare your packages in pnpm-workspace.yaml:

packages:
  - "apps/*"
  - "packages/*"

Then add Turborepo to the repo root:

pnpm add turbo -w -D

Defining the task pipeline

Turborepo is configured with a turbo.json at the root. Each task declares what it depends on and what output it produces:

{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"]
    },
    "test": {
      "dependsOn": ["build"]
    },
    "lint": {}
  }
}

The ^build in dependsOn means "build this package's dependencies first." outputs tells Turborepo which files to cache after a successful run. Now a single command builds the whole graph in the right order:

turbo build              # build everything, in dependency order
turbo run build test     # run multiple tasks
turbo build --filter=web # build just the "web" app and its deps

Caching is the payoff

The first turbo build runs normally. The second — if nothing changed — completes in milliseconds, replayed from cache. In a pipeline, that means a docs-only change doesn't rebuild your API, and a shared-package change rebuilds only the apps that actually use it. Turborepo also supports remote caching so the cache is shared across machines and CI runs, but local caching alone already removes most redundant work.

Deploying a monorepo with DeployHQ

The monorepo challenge for deployment is "build and ship only the app that changed, not the whole repo." Turborepo's --filter flag is exactly that lever.

In your build pipeline, install dependencies and build the target app:

pnpm install
turbo build --filter=web

Then point the deployment at that app's build output (for example apps/web/dist) so only the compiled app ships. Enable automatic deployments so each push builds the affected app and deploys it — the dependency graph decides what needs rebuilding, and DeployHQ ships the result.

Because the build runs on Node, set your Node version in your build configuration to match what your team develops against — the same version you'd pin locally with a Node.js version manager like fnm or Volta.

Turborepo and your task runner

Turborepo orchestrates cross-package tasks and caching. For the everyday project commands a single developer runs — start the dev server, run a migration, seed the database — a lighter command runner like just pairs well: Turborepo for the monorepo graph, just for the day-to-day menu.

Ready to ship your monorepo without rebuilding everything each time? Create a free DeployHQ account and connect your repository in minutes.