Skip to content

Monorepo Build Tools Guide — Nx and Turborepo for JavaScript and TypeScript

DodaTech Updated 2026-06-23 8 min read

In this tutorial, you'll learn about Monorepo Build Tools Guide. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.

Monorepo build tools like Nx and Turborepo manage multiple packages and applications within a single Repository by providing dependency graph analysis, parallel task execution, intelligent caching, and affected-project detection to optimize build and test pipelines.

What You'll Learn

You'll learn how to set up Nx and Turborepo for JavaScript and TypeScript monorepos, configure task pipelines with caching, use affected commands to run only what changed, and optimize CI pipelines for monorepo builds at scale.

Why Monorepo Build Tools Matter

Monorepos grow to hundreds or thousands of packages. Without build tools, running tests and builds for the entire Repository wastes hours per CI run. Nx and Turborepo solve this by computing the dependency graph, detecting affected projects, caching outputs, and running only necessary tasks in parallel.

Real-World Use

The Doda Browser monorepo contains 87 packages (shared utilities, UI components, browser extensions, and backend services). Nx-powered CI pipelines run only affected tests on each Pull Request, reducing average CI time from 68 minutes to under 4 minutes.

Prerequisites

Step 1: Nx Project Setup

Nx is a build system with first-class monorepo support, offering generators, executors, and computation caching.

# Create a new Nx monorepo
npx create-nx-workspace@latest myorg --preset=ts

cd myorg

# Generate an application and a library
nx g @nx/next:app webapp
nx g @nx/react:lib shared-ui
nx g @nx/node:lib api-client
// nx.json — Nx configuration
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx-cloud",
      "options": {
        "cacheableOperations": ["build", "test", "lint"],
        "accessToken": "your-nx-cloud-token"
      }
    }
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"]
    },
    "test": {
      "inputs": ["default", "^production", "{workspaceRoot}/jest.config.ts"]
    }
  }
}

Expected output: Running nx graph opens a browser visualization of the project dependency graph. Running nx build webapp builds the webapp and all its dependencies in the correct order.

Step 2: Affected Commands and CI

Nx's affected commands determine which projects changed based on Git history and run tasks only for those projects.

# Run tests only for affected projects
nx affected:test --base=main --head=HEAD

# Build only affected projects and their dependencies
nx affected:build --base=main --head=HEAD

# Lint affected projects
nx affected:lint --base=main --head=HEAD

# Run multiple targets for affected projects
nx affected --target=test,lint,build --base=main --head=HEAD

# Nx can also detect uncommitted changes
nx affected:test --files="libs/shared-ui/src/button.tsx"
# .github/workflows/ci.yml
name: Monorepo CI
on:
  pull_request:

jobs:
  affected:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-node@v4
      - run: npm ci
      # Only run tasks affected by the PR changes
      - run: npx nx affected -t build test lint --base=origin/main

Expected behavior: If a Pull Request changes only libs/shared-ui, Nx runs build, test, and lint only for shared-ui and any packages that depend on it — not the entire monorepo.

Step 3: Turborepo Setup

Turborepo is a simpler monorepo orchestrator focused on task scheduling and caching.

# Create a Turborepo project
npx create-turbo@latest my-turbo-app
cd my-turbo-app
// turbo.json — Turborepo configuration
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": [".env"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**"],
      "cache": true
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"],
      "cache": true
    },
    "lint": {
      "cache": true
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}
# Run all tasks with caching
npx turbo run build test lint

# Run only affected packages (Turborepo 2+)
npx turbo run build --filter=[origin/main]

# Clear cache
npx turbo daemon clean

Expected output: First turbo run build compiles everything. Subsequent runs (with no changes) complete in milliseconds by reading cached outputs. Cache is stored locally in node_modules/.cache/turbo.

Step 4: Comparison and Migration Guide

Both tools share core features but differ in philosophy and advanced capabilities.

// Nx project.json for a library
{
  "name": "shared-ui",
  "targets": {
    "build": {
      "executor": "@nx/vite:build",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/libs/shared-ui"
      }
    },
    "test": {
      "executor": "@nx/jest:jest",
      "options": {
        "jestConfig": "libs/shared-ui/jest.config.ts"
      }
    }
  }
}
# Migration from Turborepo to Nx or vice versa
# Turborepo → Nx: add nx.json and install @nx/workspace
# Nx → Turborepo: create turbo.json and remove nx.json

# Key differences:
# Nx: generators, executors, dependency graph visualization, Nx Cloud
# Turborepo: simpler setup, lighter CLI, Vercel integration

Capability comparison:

Feature Nx Turborepo
Task Orchestration Yes Yes
Local caching Built-in Built-in
Remote caching Nx Cloud Vercel Remote Cache
Affected commands Native via --filter (2.x)
Code generators Extensive None
Dependency graph Built-in viewer CLI only
Plugin ecosystem Extensive Minimal
CI optimization Distributed task execution Parallel pipeline

Expected insight: Choose Nx for large monorepos with many frameworks needing generators and advanced dependency management. Choose Turborepo for simpler monorepos where you mainly need task scheduling and caching.

Architecture

flowchart LR
    subgraph "Monorepo Packages"
        A[apps/webapp]
        B[apps/api]
        C[libs/shared-ui]
        D[libs/api-client]
        E[libs/utils]
    end
    subgraph "Build Tool"
        GRAPH[Dependency Graph]
        CACHE[Computation Cache]
        SCHED[Task Scheduler]
        AFFECT[Affected Detection]
    end
    subgraph "Tasks"
        BUILD[Build]
        TEST[Test]
        LINT[Lint]
        DEPLOY[Deploy]
    end
    A -->|depends on| C
    A -->|depends on| D
    D -->|depends on| E
    C -->|depends on| E
    B -->|depends on| D
    GRAPH --> SCHED
    AFFECT --> SCHED
    SCHED --> CACHE
    SCHED --> BUILD
    SCHED --> TEST
    SCHED --> LINT
    SCHED --> DEPLOY

Common Errors

1. Nx: Cannot find module '@nx/workspace' The Nx plugin is not installed. Run npm install -D @nx/workspace or use nx init to install the correct plugins for your project structure.

2. Turborepo: No cache found for task build First-time builds always run from scratch. Cache is populated on subsequent runs. Check that outputs in turbo.json correctly identifies build output directories.

3. Affected command detects unchanged packages Git merge-base is incorrect. Ensure fetch-depth: 0 in CI for full Git history. On local machines, run git fetch origin main before nx affected:test --base=origin/main.

4. Circular dependency detected Package A depends on B, and B depends on A (directly or transitively). Restructure to remove cycles — extract shared code into a third package that both A and B depend on.

5. Remote cache miss in CI The remote cache key (computed from inputs) differs between local and CI machines. Ensure consistent Node.js versions, operating systems, and environment variables. Use env in cache configuration to include platform-specific keys.

Practice Questions

1. How does Nx determine which projects are affected? Nx compares the Git diff between the base and head commits, finds changed files, maps them to projects, and then traverses the dependency graph to find all downstream projects that depend on changed files.

2. What is the purpose of the dependsOn configuration in turbo.json? It defines task ordering. "test": { "dependsOn": ["build"] } means the test task waits for the build task to complete first in the same package.

3. How does computation caching work in monorepo tools? Each task's inputs (source files, environment variables, dependencies) are hashed. If the same hash exists in the cache, the cached output is restored instead of re-executing the task.

4. Challenge: Set up an Nx monorepo with two applications and three shared libraries Create a workspace with a React app and a Node API app sharing three libraries: ui-components, api-client, and utils. Verify that changing utils triggers rebuilds in both applications.

5. Challenge: Remote caching with GitHub Actions Configure Nx Cloud or Turborepo remote caching in a GitHub Actions workflow. Measure the difference in CI time between cold cache (first run) and warm cache (subsequent runs on the same branch).

FAQ

Should I use Nx or Turborepo for a new monorepo?

Choose Nx if you need code generators, extensive plugin support, or plan to work with multiple frameworks. Choose Turborepo for simpler setups where you mainly need task Orchestration and caching.

Can Nx and Turborepo work with non-JavaScript projects?

Nx supports Go, Rust, Python, and other languages through community plugins. Turborepo focuses on JavaScript and TypeScript ecosystems.

Are monorepo tools only for frontend development?

No. Monorepo tools work for any project structure with multiple interdependent packages — backend services, shared libraries, documentation sites, mobile apps, and infrastructure code.

Next Steps

  • Explore JavaScript module resolution in monorepo environments
  • Learn how TypeScript project references work with Nx dependency graphs
  • Compare monorepo strategies with the monolithic vs micro-frontends guide
  • Review the Git monorepo workflows tutorial for managing large repositories

Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro