Skip to content
Published on

빌드 시스템 & 모노레포 툴 2026 완벽 가이드 - Bazel 8 · Pants 2 · Buck2 · Nx 20 · Turborepo 2 · Moon · Lerna 8 · Rush · pnpm Workspaces 심층 분석

Authors

프롤로그 — 빌드 시스템은 왜 다시 뜨거워졌나

2026년 어느 회사의 플랫폼 회의.

주니어: "JS 모노레포라 Turborepo면 충분하지 않나요?" 시니어: "그럼 백엔드 Go랑 데이터팀 Python은 어떻게 한 번에 빌드해?" 주니어: "...아."

이 짧은 대화에 빌드 시스템의 2026년이 들어있다. 한쪽엔 언어별 도구(cargo, gradle, npm 스크립트)가 있고, 다른 한쪽엔 폴리글랏(Bazel, Buck2, Pants)이 있다. 그리고 그 사이에 Nx, Turborepo, Moon 같은 태스크 러너 + 캐시 계열이 끼어든다.

이 글은 2026년 5월 기준의 전체 지형도를 한 번에 정리한다. Bazel 8의 Bzlmod 기본화, Buck2 OSS 안착, Pants 2의 점유율, Nx 20과 Turborepo 2의 경쟁, Moon의 부상, Gradle 8.10 / Maven 4 / sbt 1.10의 자바·스칼라 진영까지. 그리고 한국·일본 빅테크가 실제로 무엇을 쓰는지까지.


1장 · 2026년 빌드 시스템 지도 — 4개 축으로 나누기

빌드 시스템이라는 단어 하나에 너무 많은 것들이 섞여 있다. 정리하는 가장 쉬운 방법은 두 개의 축으로 나누는 것이다.

축 1 / 축 2단일 언어폴리글랏
로컬 캐시만cargo, npm, go buildGNU Make, just, Task
원격 캐시/실행Gradle + Develocity, Nx Cloud, Turborepo Remote CacheBazel, Buck2, Pants

세로축은 언어 지원 범위, 가로축은 캐시·분산 수준이다. 2026년의 주요 흐름은 오른쪽 아래(폴리글랏 + 원격) 칸이 빠르게 채워지고 있다는 점이다. 그리고 그 칸 안에서도 두 진영이 갈린다 — Bazel/Buck2/Pants 진영의 "선언적 그래프 + 해석적 BUILD 파일" 과 Nx/Turborepo/Moon 진영의 "JSON/YAML 설정 + 영향 받은 프로젝트만 실행".

선택의 출발점은 단순하다.

  1. 단일 언어 + 작은 팀 → 그 언어 기본 툴 (cargo, gradle, npm).
  2. 단일 언어 + 큰 모노레포 → 그 언어 기본 + 원격 캐시 (Develocity, Nx Cloud).
  3. JS/TS 위주 + 다중 패키지 → pnpm workspaces / Nx / Turborepo.
  4. 폴리글랏 + 큰 규모 → Bazel / Buck2 / Pants.

2장 · 모노레포 vs 폴리레포 — 2026년의 답

이 논쟁은 거의 정리됐다. 답은 "둘 다 쓴다, 다만 모노레포가 기본값이 됐다" 다.

모노레포의 장점: atomic 변경 (한 PR로 라이브러리·서비스·테스트 동시 변경), 단일 의존성 그래프, 공유 인프라(빌드·CI·린트), 검색·리팩터링이 IDE 하나로 끝남.

폴리레포의 장점: 권한 격리, 빌드 시간 격리, 팀별 자율성, 작은 리포의 단순함.

2026년 절충: "한 회사 안에 여러 모노레포". 예컨대 platform-monorepo(인프라·플랫폼), product-monorepo(서비스), data-monorepo(파이프라인). 각각은 모노레포지만 회사 전체로 보면 폴리레포. Google/Meta/Microsoft 일부 조직이 이 패턴을 쓴다. 작은 회사라면 그냥 하나의 모노레포가 답이다.

Trunk-based development + feature flags + change detection(아래 21장) 이 세 가지가 결합되면 모노레포의 단점 대부분이 사라진다.


3장 · Bazel 8 — 폴리글랏 빌드의 표준

Bazel은 Google이 내부 빌드 시스템 Blaze를 OSS로 푼 것이다. 2026년 5월 현재 안정 버전은 Bazel 8.x, LTS는 7.x. 핵심 변화는 Bzlmod(MODULE.bazel) 가 기본이 되고 WORKSPACE 모드가 deprecate 된 것이다.

라이선스는 Apache 2.0. 사용처는 Google, X(구 Twitter), Stripe, Pinterest, Spotify, Snap, Dropbox, Coupang, Mercari 등.

핵심 개념.

  • BUILD.bazel: 디렉터리당 한 개, 그 디렉터리의 빌드 타겟 선언.
  • WORKSPACE / MODULE.bazel: 리포 루트, 외부 의존성·툴체인 선언.
  • Starlark: Python 부분집합, 빌드 규칙을 작성하는 언어.
  • rules: 언어별 규칙 집합 (rules_go, rules_python, rules_js, rules_rust, rules_java).
  • sandbox: 모든 액션을 격리된 디렉터리에서 실행, hermetic 보장.
  • remote cache / remote execution: 액션 결과를 해시로 캐시, 결과 없으면 원격 워커에서 실행.

가장 단순한 Go 바이너리 빌드.

# BUILD.bazel
load("@io_bazel_rules_go//go:def.bzl", "go_binary", "go_library")

go_library(
    name = "hello_lib",
    srcs = ["main.go"],
    importpath = "example.com/hello",
)

go_binary(
    name = "hello",
    embed = [":hello_lib"],
)
bazel build //cmd/hello:hello
bazel test //...
bazel query 'deps(//cmd/hello:hello)' | head

Bzlmod 의존성 선언.

# MODULE.bazel
module(name = "myrepo", version = "0.1.0")

bazel_dep(name = "rules_go", version = "0.55.0")
bazel_dep(name = "gazelle", version = "0.41.0")

go_deps = use_extension("@gazelle//:extensions.bzl", "go_deps")
go_deps.from_file(go_mod = "//:go.mod")
use_repo(go_deps, "com_github_pkg_errors")

Bazel의 강점은 그래프 + 캐시 + 원격 실행이 깊게 통합되어 있다는 것이다. 약점은 학습 곡선과 BUILD 파일을 손으로 쓰는 부담 (Gazelle 같은 자동 생성기로 완화).


4장 · Buck2 (Meta) — Rust로 다시 쓴 Buck

Buck1은 Meta가 2013년에 만든 Bazel 사촌. 2023년 Meta는 이를 Rust로 처음부터 다시 쓰고 OSS로 풀었다 — Buck2. 2026년 현재 Meta 사내 빌드의 표준이고, OSS 사용처도 늘었다.

Bazel과의 비교.

항목BazelBuck2
구현JavaRust
설정 언어StarlarkStarlark
액션 그래프rule 평가 시 결정Dynamic Dependencies로 빌드 중 결정 가능
원격 실행RE API (BuildBuddy, EngFlow)RE API (BuildBuddy, EngFlow)
라이선스Apache 2.0Apache 2.0
주요 사용처Google, X, StripeMeta, Discord

가장 큰 차이는 dynamic dependencies. Bazel은 BUILD 평가 → action graph → 실행이 분리되어 있어 빌드 도중 그래프가 바뀔 수 없다. Buck2는 일부 노드에서 빌드 중 추가 입력을 선언할 수 있어 OCaml .ml/.mli처럼 컴파일 결과에 의존하는 의존 관계를 자연스럽게 표현한다.

# BUCK
load("@prelude//rules.bzl", "cxx_binary", "cxx_library")

cxx_library(
    name = "hello_lib",
    srcs = ["hello.cc"],
    headers = ["hello.h"],
)

cxx_binary(
    name = "hello",
    srcs = ["main.cc"],
    deps = [":hello_lib"],
)
buck2 build //cpp/hello:hello
buck2 test //...
buck2 cquery 'deps(//cpp/hello:hello)'

Bazel에서 마이그레이션할 가치가 있을까? 보통은 없다. 신규 폴리글랏 모노레포 + Meta 영향권 + 동적 의존성이 정말 필요한 경우에만 고려.


5장 · Pants 2 — Python 모노레포의 사실상 표준

Pants v1은 2014년 Twitter가 만든 Java/Scala 빌드 시스템이었다. v2부터는 Toolchain Labs가 처음부터 다시 만들어 Python 우선 폴리글랏으로 포지셔닝한다. 2026년 5월 안정 버전 Pants 2.27.

라이선스 Apache 2.0, 사용처 Slack, IBM, Pico, Toolchain.

Pants 2의 차별점.

  • Python-first: pytest, mypy, ruff, pyright, black, flake8 등 Python 도구 일급 지원.
  • 자동 의존성 추론: import 그래프를 분석해 BUILD 파일에 deps를 자동 추가.
  • Lockfile-aware: PEP 621/pyproject.toml과 lockfile 통합.
  • Remote caching: BuildBuddy, EngFlow 호환.
# pants.toml
[GLOBAL]
pants_version = "2.27.0"
backend_packages = [
  "pants.backend.python",
  "pants.backend.python.lint.ruff",
  "pants.backend.python.typecheck.mypy",
  "pants.backend.docker",
]

[python]
interpreter_constraints = ["==3.12.*"]
# src/python/myapp/BUILD
python_sources(name="lib")
python_tests(name="tests", dependencies=[":lib"])
pex_binary(name="bin", entry_point="myapp.main:main")
pants tailor ::                # BUILD 파일 자동 생성
pants lint test check ::       # 전체 lint/test/typecheck
pants --changed-since=main test  # 변경된 것만
pants package src/python/myapp:bin

Python 모노레포라면 Pants 2가 거의 디폴트 선택지다. mypy/ruff 캐시까지 처리해 주는 게 결정적이다.


Bazel·Buck2·Pants 모두 Remote Execution API(REAPI) 라는 gRPC 표준을 따른다. 캐시(action result, CAS)와 실행(worker)을 분리해서, 클라이언트는 캐시 미스면 원격 워커에 실행을 위임한다.

2026년 주요 백엔드.

제품회사특징
BuildBuddyBuildBuddy Inc오픈코어, UI 좋음, GCP/AWS SaaS + 셀프호스트
EngFlowEngFlow엔터프라이즈 포커스, Spotify·Tesla 도입
NativeLinkTraceMachinaOSS, Rust, 학습 단계지만 빠름
BuildbarnOSS오픈소스, 직접 운영

BuildBuddy 설정 예 (.bazelrc).

build --bes_results_url=https://app.buildbuddy.io/invocation/
build --bes_backend=grpcs://remote.buildbuddy.io
build --remote_cache=grpcs://remote.buildbuddy.io
build --remote_executor=grpcs://remote.buildbuddy.io
build --remote_header=x-buildbuddy-api-key=YOUR_API_KEY

이 한 블록만으로 캐시 + 실행 + 빌드 이벤트 스트림(BES, 웹 UI에서 빌드 추적) 이 켜진다. 큰 모노레포에선 빌드 시간이 5~10배 줄어드는 경우가 흔하다.


7장 · Nx 20 — JS/TS 모노레포의 강자

Nx는 Nrwl(현 Nx)가 만든 JS/TS 모노레포 도구다. 2026년 5월 현재 Nx 20.x. 라이선스 MIT, 클라우드 호스팅은 Nx Cloud(유료 SaaS).

Nx의 핵심 가치 두 가지.

  1. 로컬·원격 캐시: 태스크 결과(빌드, 테스트, 린트 출력)를 해시로 캐시.
  2. affected: git diff 기반으로 변경 영향을 받은 프로젝트만 실행.
npx create-nx-workspace@latest myorg --preset=ts
cd myorg
nx g @nx/react:app web
nx g @nx/node:app api
nx g @nx/js:lib shared
// nx.json
{
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx-cloud",
      "options": {
        "cacheableOperations": ["build", "lint", "test", "e2e"],
        "accessToken": "YOUR_NX_CLOUD_TOKEN"
      }
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*"],
    "production": ["default", "!{projectRoot}/**/*.spec.ts"]
  }
}
nx run-many -t build       # 모든 프로젝트 빌드
nx affected -t test        # 변경 영향 프로젝트만 테스트
nx graph                   # 프로젝트 의존성 그래프 시각화
nx release                 # 버전·changelog·publish

Nx 20의 새 기능: Atomizer(테스트 분할), Custom Conformance Rules(모노레포 규칙 검사), Self-Healing CI(실패한 e2e를 자동 재시도+분석). Lerna 인수 후 통합이 거의 완료되어 Lerna는 Nx의 별칭에 가깝다.


8장 · Turborepo 2 — Vercel의 JS 모노레포 도구

Turborepo는 2021년 Jared Palmer가 만든 모노레포 빌드 시스템. 2022년 Vercel 인수. 2024년 Turborepo 2.0에서 핵심 부분이 Rust로 다시 쓰였고, 2026년 현재 2.x가 안정.

Nx와의 비교.

항목NxTurborepo
철학"스마트한" 워크스페이스 (생성기·플러그인·그래프)"단순한" 태스크 러너 + 캐시
설정nx.json + project.jsonturbo.json
코드 생성풍부한 generator거의 없음
캐시로컬 + Nx Cloud로컬 + Remote Cache (Vercel 기본 무료, 셀프호스트 가능)
분산 실행Nx Agents없음 (CI shard로 우회)
언어JS/TS 중심, 일부 폴리글랏JS/TS 전용
학습 곡선중상낮음
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"],
      "inputs": ["src/**", "package.json", "tsconfig.json"]
    },
    "test": { "dependsOn": ["^build"], "outputs": ["coverage/**"] },
    "lint": { "outputs": [] },
    "dev": { "cache": false, "persistent": true }
  }
}
turbo run build               # 전체 빌드 (캐시 적중분 skip)
turbo run test --filter=...[origin/main]  # 변경분만
turbo run dev --parallel      # 개발 서버 병렬
turbo prune --scope=web       # 특정 앱만 추려서 Docker 빌드

Turborepo의 가장 큰 무기는 단순함과 Vercel 통합. CI에서 TURBO_TOKEN + TURBO_TEAM 환경변수만 주면 Vercel Remote Cache가 자동으로 켜진다. Next.js·Remix 위주의 팀은 Turborepo가 가장 마찰이 적다.


9장 · Moon (moonrepo) — Rust로 만든 폴리글랏 다크호스

Moon은 2022년 등장한 Rust 기반 빌드 시스템. 만든 사람은 Lerna·Yarn 출신의 Miles Johnson. 라이선스 MIT. JS/TS·Python·Rust·Go·Deno·Bun을 한 도구로 묶는 게 목표.

Nx/Turborepo와 다른 점.

  • 언어 무관: lang.toml로 toolchain (Node, Deno, Bun, Rust, Python) 버전 핀.
  • Project graph: Bazel처럼 디렉터리 단위, 하지만 설정은 YAML.
  • Affected: Nx와 동일한 컨셉.
  • Mise 통합: 버전 매니저 Mise와 결합해 toolchain 부트스트랩.
# .moon/workspace.yml
projects:
  - 'apps/*'
  - 'packages/*'

vcs:
  manager: 'git'
  defaultBranch: 'main'

runner:
  cacheLifetime: '7 days'
  archivableTargets: ['build', 'test']
# apps/web/moon.yml
language: 'typescript'
type: 'application'
dependsOn:
  - 'shared'
tasks:
  build:
    command: 'next build'
    outputs: ['.next']
  test:
    command: 'vitest run'
moon run web:build
moon ci             # 변경 영향 받은 모든 태스크
moon dep-graph

Moon은 아직 작지만, Rust 속도 + 폴리글랏 + YAML 설정 조합이 매력적이다. Bazel은 부담스럽고 Turborepo는 JS 전용이라 답답한 팀이 노릴 만하다.


10장 · Lerna 8 · Rush · pnpm workspaces — JS 모노레포 3 가지 길

여전히 가벼운 JS 모노레포 옵션이 셋 있다.

Lerna 8: 2022년 Nrwl이 인수해 사실상 Nx의 일부가 됐다. 새 프로젝트라면 그냥 Nx를 직접 쓰는 게 낫지만, 기존 Lerna 리포는 Nx 캐시·affected를 그대로 받을 수 있다.

// lerna.json
{ "version": "independent", "npmClient": "pnpm", "useNx": true }
lerna run build --since=origin/main
lerna publish

Rush (Microsoft Rush Stack): pnpm 위에 강한 정책(엄격한 phantom dependency 차단, 변경 파일 검사) 을 얹은 도구. Microsoft, Microsoft Office Online, Azure 일부에서 사용. 큰 JS 모노레포의 엄격함이 필요할 때.

rush install
rush build
rush change         # PR 전 변경 파일 작성
rush publish

pnpm workspaces (9.x): 가장 단순. pnpm-workspace.yaml + package.jsonworkspaces 필드. 캐시·affected는 없지만 작은 모노레포(20개 미만 패키지) 에 적합.

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
pnpm install
pnpm -r build                  # 모든 워크스페이스 빌드
pnpm --filter=@org/web build   # 특정 패키지만
pnpm --filter='...[origin/main]' test  # 변경 영향만 (pnpm 9+)

선택 가이드: 작은 팀 + JS 전용 + 단순 선호 → pnpm workspaces. 중대형 + Vercel 친화 → Turborepo. 중대형 + 풍부한 도구·정책 → Nx. 대형 + 엄격 정책 + MS 친화 → Rush.


11장 · 자바·코틀린 진영 — Gradle 8.10 + Maven 4

JVM은 자체 빌드 도구 생태계가 두텁다. 2026년 5월 기준 안정 버전.

Gradle 8.10+: Groovy/Kotlin DSL, 의존성 관리, 멀티 프로젝트. 핵심 캐시 기능 두 가지.

  • build cache: 태스크 결과 캐시 (로컬 + 원격).
  • configuration cache: 빌드 설정 단계 결과 캐시 (대형 프로젝트에서 수 초~수십 초 절약).
  • Develocity(구 Gradle Enterprise): 원격 캐시 + 빌드 스캔 + 테스트 인사이트 SaaS.
// build.gradle.kts
plugins {
    java
    application
    id("org.springframework.boot") version "3.4.1"
}

group = "com.example"
version = "0.1.0"

repositories { mavenCentral() }
dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
}

tasks.test { useJUnitPlatform() }
./gradlew build --build-cache --configuration-cache
./gradlew :api:test
./gradlew dependencies

Maven 4 (2025년 GA): pom.xml의 안정성을 유지하면서 빌드 그래프, 병렬화, daemon (mvnd)을 강화. Spring 생태계의 거대한 관성으로 여전히 1순위. mvnd(Maven Daemon)를 쓰면 JVM 워밍업이 없어 체감 속도가 Gradle 수준에 근접한다.

./mvnw -T 1C clean install      # CPU 코어당 1 스레드 병렬
mvnd -T 1C clean install        # daemon 모드

JVM 모노레포라면: 신규 프로젝트는 Gradle + Develocity, 기존/SI 프로젝트는 Maven 4 + mvnd가 합리적이다.


12장 · sbt 1.10 · Mill — Scala 진영

Scala는 별도 글에서도 다루지만 빌드 관점에서 짧게.

sbt 1.10: Scala의 디폴트, incremental 컴파일이 강점. 학습 곡선이 가파르다는 평이 영원한 불만.

// build.sbt
ThisBuild / scalaVersion := "3.6.0"
lazy val root = (project in file("."))
  .settings(
    name := "myapp",
    libraryDependencies ++= Seq(
      "org.typelevel" %% "cats-effect" % "3.5.4",
      "org.scalatest" %% "scalatest" % "3.2.19" % Test,
    )
  )

Mill (Lihaoyi): Scala/Java/JS 빌드를 Scala로 기술. sbt보다 명료하고 빠르다는 평. 메인스트림은 아니지만 신규 Scala 팀이 종종 채택.

// build.mill
package build
import mill._, scalalib._
object app extends ScalaModule {
  def scalaVersion = "3.6.0"
  def ivyDeps = Agg(ivy"org.typelevel::cats-effect:3.5.4")
}

Scala 모노레포가 정말 크면 Bazel + rules_scala 가 사실상 유일한 답이지만, 그 단계까지 가는 팀은 극소수다.


13장 · C/C++ — CMake 3.31 + Ninja 1.12 / Meson / Bazel

C/C++는 빌드 시스템 춘추전국 시대가 가장 오래 갔다. 2026년의 정리.

CMake 3.31 + Ninja 1.12: 사실상 표준. CMake는 빌드 시스템이 아니라 빌드 시스템 생성기(Makefile, Ninja, MSBuild 등 생성). Ninja는 그 결과를 가장 빠르게 실행한다.

# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(myapp CXX)
set(CMAKE_CXX_STANDARD 23)

add_library(mylib STATIC src/foo.cc src/bar.cc)
target_include_directories(mylib PUBLIC include)

add_executable(myapp src/main.cc)
target_link_libraries(myapp PRIVATE mylib)
cmake -S . -B build -G Ninja
cmake --build build -j
ctest --test-dir build

Meson + Ninja: CMake의 사촌, 더 깔끔한 문법(Python 비슷). GNOME, systemd 등에서 사용.

Bazel + rules_cc: 대규모 C/C++ 폴리글랏 모노레포의 답. Google·Stripe·Pinterest의 C++ 서비스가 이 경로.

GNU Make: 여전히 작은 프로젝트의 1순위. 학습 곡선이 가장 평탄.


14장 · Rust — Cargo workspaces + cargo-nextest

Rust 모노레포는 거의 모든 경우 Cargo workspaces 로 충분하다.

# Cargo.toml (root)
[workspace]
resolver = "2"
members = ["crates/*", "services/*"]

[workspace.dependencies]
tokio = { version = "1.42", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
cargo build --workspace
cargo test --workspace
cargo nextest run --workspace        # 더 빠른 테스트 러너
cargo metadata --format-version 1    # 의존성 그래프

원격 캐시가 필요하면 sccache(Mozilla) 가 표준. S3·GCS·Redis·memcached·로컬 디스크 백엔드 지원.

export RUSTC_WRAPPER=sccache
export SCCACHE_BUCKET=my-sccache-bucket
cargo build --release
sccache --show-stats

대규모 폴리글랏에 Rust가 끼면 Bazel + rules_rust 도 선택지지만, 도입 부담이 크다. 회사 단위로 Bazel 표준이 없으면 sccache + Cargo가 사실상 정답.


15장 · Go — go modules + gomonorepo 패턴

Go는 모듈 시스템이 단순해서 모노레포가 자연스럽다. 한 리포에 하나의 go.mod를 두고 internal/로 패키지 경계를 긋는 게 표준.

myrepo/
  go.mod
  cmd/
    api/main.go
    worker/main.go
  internal/
    auth/
    storage/
  pkg/
    publicapi/
go build ./...
go test ./...
go vet ./...
go test -count=1 -run TestFoo ./internal/auth

캐시·원격 실행이 필요하면 Bazel + rules_go + gazelle 조합이 가장 성숙. Gazelle는 BUILD.bazelgo.mod에서 자동 생성한다.

bazel run //:gazelle
bazel run //:gazelle -- update-repos -from_file=go.mod -to_macro=deps.bzl%go_dependencies

Pinterest·Twitter·Coupang의 Go 서비스가 이 경로다.


16장 · Mise (구 rtx) · just · Task — 가벼운 태스크 러너

빌드 시스템과 별개로, 반복 명령을 짧게 부르는 도구가 있다. 셸 스크립트·Makefile의 후계자들.

Mise (구 rtx): asdf 호환 버전 매니저 + 태스크 러너. Rust로 작성. 한 도구로 Node·Python·Go·Rust·Ruby·Bun 버전을 잠그고 태스크까지 정의.

# mise.toml
[tools]
node = "22"
python = "3.12"
go = "1.23"

[tasks.build]
description = "Build all"
run = "pnpm -r build"

[tasks.test]
description = "Run tests"
depends = ["build"]
run = "pnpm -r test"
mise install        # 도구 설치
mise run build
mise run test

just: Make의 현대판. 깔끔한 문법, 의존성 없음.

# justfile
default:
    @just --list

build:
    pnpm -r build

test: build
    pnpm -r test

release version:
    git tag v{{version}}
    git push origin v{{version}}

Task (taskfile.dev): YAML 기반 태스크 러너, Go로 작성.

# Taskfile.yml
version: '3'
tasks:
  build:
    cmds:
      - pnpm -r build
  test:
    deps: [build]
    cmds:
      - pnpm -r test

이 셋은 빌드 그래프 도구가 아니라 명령 단축어다. 대형 모노레포에서도 entry point로 쓰기 좋다 — just ci 가 내부적으로 bazel test //...nx affected -t test를 부르는 식.


17장 · 원격 캐시 — Bazel BES vs Nx Cloud vs Turborepo Remote Cache

세 도구의 원격 캐시 방식이 다르다.

시스템캐시 키저장 위치백엔드
Bazelaction hash (입력 + 명령 + 환경)CAS (Content Addressable Storage)BuildBuddy, EngFlow, Buildbarn
Nx Cloudtask hash (입력 + 명령 + 환경)Nx Cloud SaaS or self-hostNx Cloud (proprietary)
Turborepo Remote Cachetask hashVercel SaaS or self-hostVercel, Turborepo Server (OSS)

Bazel의 강점: REAPI 표준, 멀티 백엔드, 캐시 hit이 거의 항상 동작 (sandboxing 덕분).

Nx Cloud의 강점: 웹 UI, 실패한 빌드 인사이트, Nx Agents(분산 실행) 통합.

Turborepo의 강점: 설정이 가장 단순(환경변수 2개), Vercel CI와 자동 통합.

Self-host 옵션이 모두 있지만, 운영 부담은 BuildBuddy/Buildbarn >> Nx Cloud (Helm chart) >> Turborepo Server (Docker 컨테이너 하나).


18장 · Hermetic builds + content-addressed cache — 재현성의 본질

"빌드가 어제는 됐는데 오늘 안 됨" 의 근본 원인은 숨어있는 입력(환경변수, 시스템 라이브러리, 시계, 네트워크). 이걸 해결하는 게 hermetic build와 content-addressed cache.

Hermetic: 빌드 액션의 입력을 명시적으로 선언 (소스 + 도구 + 환경변수), 외부 접근 차단 (sandbox). Bazel·Buck2·Pants가 기본으로 한다.

Content-addressed: 입력 해시가 같으면 출력도 같다고 가정. 입력이 1바이트라도 다르면 새로 빌드, 같으면 캐시 적중.

input_hash = sha256(sources + tools + env + command)
output: stored under output_hash
cache_key: input_hash → output_hash

Nix도 같은 철학이다 (Bazel과 Nix는 다른 도구지만 같은 아이디어). 재현 가능한 CI/CD가 진짜 가능해진다.


19장 · 컨테이너 빌드 — BuildKit / Buildah / Kaniko / Earthly

빌드 시스템 글이 컨테이너로 끝나는 이유: 2026년 모든 서비스가 OCI 이미지로 배포되고, 빌드 시스템 출력 → 컨테이너 이미지 변환이 빌드 파이프라인의 마지막 단계다.

도구데몬 필요특징
Docker BuildKit필요(dockerd)표준, 캐시 마운트·SBOM·provenance
Buildah / Podman build불필요데몬리스, Red Hat
Kaniko불필요컨테이너 안에서 컨테이너 빌드, K8s CI 친화
Earthly데몬 사용Dockerfile + Makefile 결합, 캐시 강력
ko (Go 전용)불필요Go 바이너리를 distroless 이미지로 즉시 패키징
Jib (JVM 전용)불필요Maven/Gradle 플러그인으로 Docker 없이 이미지 빌드

Bazel은 rules_oci(구 rules_docker 후속) 로 OCI 이미지를 hermetic하게 만든다. 이미지 레이어가 입력 해시에 따라 동일하게 재현된다.

# BUILD.bazel
load("@rules_oci//oci:defs.bzl", "oci_image")
oci_image(
    name = "api_image",
    base = "@distroless_base",
    entrypoint = ["/api"],
    tars = [":api_layer"],
)

20장 · 글로벌 빅테크의 빌드 시스템

회사메인 빌드
GoogleBlaze (Bazel 사내판)
MetaBuck2
MicrosoftRush + 자체 시스템
AmazonBrazil (자체) + Cargo / Maven
X (구 Twitter)Bazel (Pants에서 마이그레이션)
PinterestBazel (Python/Java/Go)
StripeBazel
SpotifyBazel + EngFlow
SnapBazel
DropboxBazel (Python 일부 Pants)
SlackPants (Python·TS)
VercelTurborepo
ShopifyBazel (서비스), nx/turborepo (storefront)
GitHub자체 + Bazel
DiscordBuck2

폴리글랏 + 대규모는 Bazel/Buck2/Pants 셋으로 수렴한다.


21장 · 한국·일본 사례

한국

  • Coupang: Bazel 광범위 사용. Search·Logistics·iOS/Android 일부 Bazel. C++ 검색 인프라가 Bazel hermetic 위에서 돈다.
  • Toss / Viva Republica: 프론트엔드 Turborepo. 백엔드는 Gradle 중심.
  • Naver: 광범위. NHN/Naver Pay 일부 Bazel, 프론트엔드 팀 다수 Turborepo·Nx.
  • Kakao: Gradle/Maven 중심, 프론트는 Turborepo / pnpm workspaces.
  • Woowa Brothers (배민): Gradle + Spring 중심. 프론트는 Nx/Turborepo.
  • 당근: pnpm workspaces + Turborepo가 표준. 일부 Nx 도입.

일본

  • Mercari: Bazel 광범위. Microservices Go/Java를 Bazel + BuildBuddy.
  • LINE Yahoo: Bazel(LY), Gradle(LINE 일부). 검색·광고 인프라는 Bazel.
  • CyberAgent / Ameba: Nx + Turborepo. Bazel은 일부 광고 플랫폼.
  • Recruit / Indeed: Bazel 광범위. Indeed는 monorepo + Bazel 발표 다수.
  • DeNA: Gradle 중심 + 일부 Bazel.
  • Rakuten: Gradle + Maven, Bazel 일부.

흥미로운 점: 일본 빅테크의 Bazel 채택률이 한국보다 높다. Mercari·Indeed·LY의 영향.


22장 · 언제 무엇을 쓸 것인가 — 결정 트리

마지막으로 정리.

  1. 소규모 JS 팀 (~5명, ~10 패키지)pnpm workspaces 단독.
  2. 중규모 JS/TS 팀 (~30명, ~50 패키지) + Vercel/Next.js 위주Turborepo 2 + Vercel Remote Cache.
  3. 중규모 JS/TS 팀 + 풍부한 도구·정책 필요Nx 20 + Nx Cloud.
  4. JS + Python + Go 폴리글랏 모노레포Moon 또는 Bazel.
  5. Python 모노레포 (데이터·ML 팀)Pants 2.
  6. JVM 신규Gradle 8.10 + Develocity.
  7. JVM 레거시/SIMaven 4 + mvnd.
  8. Rust 모노레포Cargo workspaces + sccache + cargo-nextest.
  9. Go 모노레포 → 단일 go.mod + 필요시 Bazel + Gazelle.
  10. C/C++CMake + Ninja (작은 팀) 또는 Bazel (대규모).
  11. Scalasbt 또는 Mill, 정말 크면 Bazel + rules_scala.
  12. 거대 폴리글랏 + 원격 실행 필수Bazel + BuildBuddy/EngFlow, 또는 Buck2.

가장 흔한 실수는 "유행 따라 Bazel 도입했다가 6개월 뒤 후회" 다. 현재 팀의 빌드 시간이 정말 병목이고, 그 병목이 원격 캐시/실행으로 해결되며, 유지보수 인력이 있다 는 세 조건이 맞을 때만 폴리글랏 빌드 시스템을 고려해라. 그렇지 않으면 그 언어의 기본 도구가 거의 항상 옳다.


참고 자료


에필로그 — "빌드는 결국 그래프"

빌드 시스템 30년의 핵심을 한 줄로 요약하면 "입력 → 출력의 방향 그래프, 그래프의 노드를 최대한 재사용해라" 다. Make가 했던 일을 Bazel은 sandboxing + 원격 실행으로, Turborepo는 JS만의 단순한 형태로, Pants는 Python 친화적으로 다시 쓰고 있다.

도구는 바뀌어도 "내 빌드의 입력을 정확히 안다, 출력을 캐시한다, 같은 입력이면 다시 안 한다" 는 원칙은 그대로다. 2026년의 폴리글랏 빌드 시스템은 이 원칙을 여러 언어·여러 머신에 걸쳐 적용한다. 작은 팀이라면 그 원칙을 가장 가까이서 구현한 도구(pnpm + Turborepo, Cargo, Gradle)로 충분하고, 큰 팀은 어쩌면 Bazel을 피할 수 없을지도 모른다.

마지막으로 한 가지 — 빌드 시스템의 성공은 "누가 BUILD 파일을 유지보수하느냐" 에 달려 있다. 도구가 아니라 사람의 문제다. Bazel을 도입하든 Nx를 도입하든, 빌드 인프라 전담자 1~2명이 없으면 절반 정도만 성공한다. 그 인력 예산이 없다면, 그 회사에 맞는 빌드 시스템은 더 단순한 도구일 가능성이 높다.