Sachith Dassanayake Software Engineering Bazel/Nx for large repos — Cheat Sheet — Practical Guide (Jun 22, 2026)

Bazel/Nx for large repos — Cheat Sheet — Practical Guide (Jun 22, 2026)

Bazel/Nx for large repos — Cheat Sheet — Practical Guide (Jun 22, 2026)

Bazel/Nx for large repos — Cheat Sheet

Level: Intermediate

Last updated: June 22, 2026

Introduction

Managing large repositories is a common challenge in modern software engineering, especially when scaling teams, builds, and CI/CD pipelines. Bazel and Nx are two leading build systems designed to handle monorepos and multi-language projects efficiently. This cheat sheet offers a practical, focused guide for engineers familiar with build tools but new to Bazel and Nx, specifically outlining how to use them effectively in large codebases.

Prerequisites

  • Basic understanding of monorepos and incremental build concepts.
  • Some familiarity with command line interfaces and build tooling.
  • Node.js (>=16.x) installed, for Nx (v15+ recommended).
  • JDK 11 or higher, for Bazel (stable 6.x series as of mid-2026).
  • Workspace with an existing large repo or a sizeable sample project.
  • Familiarity with relevant languages and stacks (Bazel supports Java, C++, Go, Python, TypeScript, etc.; Nx focuses on JavaScript/TypeScript and some polyglot support).

When to choose Bazel vs Nx

Bazel is ideal for polyglot environments demanding high-performance, hermetic builds with reproducibility guarantees. It excels with C++, Java, Python, and complex native builds, and scales excellently in extremely large repos (thousands of targets). Its configuration is more verbose but very precise and flexible.

Nx is tailored for JavaScript and TypeScript monorepos, especially with front-end frameworks like Angular, React, or Node.js backends. It provides a rich developer experience with tooling around generators, executors, and caching built-in. Nx’s graph-based task execution and incremental builds simplify managing large frontend/backend projects but are less suited for native or non-JS-heavy projects.

Both tools support caching and remote execution, but Bazel’s remote execution features are more mature for cross-language and cross-team scaling.


Hands-on steps

1. Initialize your workspace

Bazel (stable 6.x+)

# Create WORKSPACE file at repo root
touch WORKSPACE

# Add build files (BUILD or BUILD.bazel) to directories containing source code,
# defining targets for libraries, binaries, tests, etc.

Nx (v15+)

npm create nx-workspace@latest my-nx-repo
cd my-nx-repo

# Choose preset: empty, react, angular, node, nest, etc.
# This scaffolds workspace with nx.json, workspace.json/project.json files.

2. Define targets and dependencies

Bazel:

Create BUILD.bazel files to specify cc_library, java_library, ts_library, py_library, and tests. Use deps to express dependencies precisely. This explicit declaration is critical for Bazel’s correctness and caching.

cc_library(
    name = "foo_lib",
    srcs = ["foo.cc"],
    hdrs = ["foo.h"],
    deps = [":bar_lib"],
)

Nx:

Projects are defined in workspace.json or individual project.json files. Use the built-in generators to scaffold new apps/libs, which auto-manage dependencies and affected graph.

{
  "name": "my-lib",
  "root": "libs/my-lib",
  "sourceRoot": "libs/my-lib/src",
  "projectType": "library",
  "targets": {
    "build": {
      "executor": "@nrwl/web:build",
      "options": { ... }
    },
    "test": {
      "executor": "@nrwl/jest:jest",
      "options": { ... }
    }
  }
}

3. Use incremental and cached builds

Bazel

Bazel automatically caches results locally and can be configured to use remote caching/execution with --remote_cache flags. Always add bazel commands to your CI scripts to benefit from caching. You can also run bazel build --incremental by default to improve developer iteration speed.

Nx

Nx supports local and distributed caching with commands like:

nx build my-app --cache
nx test my-lib --cache

Distributed caching can be enabled with Nx Cloud or custom remote caching adapters (v15+). This speeds up CI by reusing previous build/test artifacts.

4. Run targeted commands for affected projects

Bazel:

Use bazel query to understand dependencies, then build or test subsets:

bazel query 'deps(//my/package:target)'          # List dependencies
bazel build //my/package:target                    # Build single target
bazel test //my/package:target                     # Test target

Nx:

Run commands only on affected projects since the last commit or branch:

nx affected --target=build --base=main --head=HEAD
nx affected:test --base=origin/main --parallel

Common pitfalls

  • Bazel: Overly complex BUILD files can slow onboarding; prefer automated tooling to generate these when possible (e.g. bazel buildifier).
  • Unmanaged dependencies or third-party code not declared properly lead to non-hermetic builds and cache misses.
  • Remote execution setup requires detailed environment parity; missing toolchains or platforms cause failures.
  • Nx: Mixing incompatible executors/plugins can cause unexpected failures or slow builds.
  • Ignoring dependency graph updates leads to running more affected projects than necessary, wasting CI resources.
  • Using outdated Node.js or Nx plugin versions triggers deprecation warnings and reduces performance.

Validation

Verify the correctness and efficacy of your setup by:

  • Running bazel build //... --explain=build.log --verbose_explanations to monitor build graphs and cache hits.
  • Using nx dep-graph to visualise project dependencies and verify changes correlate to affected projects.
  • Executing bazel test //... --test_output=errors or nx test --all --parallel to ensure tests pass.
  • Measuring build times and cache hit rates over CI runs to identify regressions.
  • Running incremental builds locally and verifying only affected targets/builds run.

Checklist / TL;DR

  • Choose Bazel when supporting multi-language, hermetic builds with heavy native code and remote execution needs.
  • Choose Nx for JS/TS-heavy, frontend/backend monorepos prioritising developer DX with built-in generators and plugins.
  • Start with clean WORKSPACE or Nx workspace files; avoid large manual edits.
  • Explicitly declare dependencies; leverage generators and linters.
  • Enable remote/local caching early to speed up CI and local dev.
  • Use targeted builds/tests via Bazel query or Nx affected commands.
  • Regularly review build graphs and dependency structure to avoid unnecessary work.
  • Pin tooling versions and update periodically respecting compatibility matrices.

References

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Related Post