Monorepo: Turborepo vs Nx vs Bun workspaces
3 tool monorepo. Turborepo = simple caching. Nx = full opinionated. Bun workspaces = minimal native. Saya pakai keduanya, verdict tergantung scale.
TL;DR
- Bun workspaces: Recommended untuk monorepo kecil 2-5 package
- Turborepo: Recommended untuk monorepo medium 5-20 package, build caching critical
- Nx: Recommended untuk monorepo besar 20+ package, full opinionated structure
Konteks
Project monorepo saya:
- SaaS klinik dental: Bun workspaces (3 package: api, web, shared)
- SaaS billing fotograf: Turborepo (5 package: api, web-admin, web-customer, shared-types, mobile)
- Eksperimen Nx: 1 try, bailed setelah 3 hari karena over-engineered
Bun workspaces
Setup
// package.json (root)
{
"name": "my-monorepo",
"workspaces": ["packages/*", "apps/*"]
}
my-monorepo/
├── apps/
│ ├── api/
│ │ └── package.json
│ └── web/
│ └── package.json
├── packages/
│ └── shared/
│ └── package.json
└── package.json
Reference shared package di app:
// apps/api/package.json
{
"dependencies": {
"@my/shared": "workspace:*"
}
}
Pro
- Zero config: Bun handle linking otomatis
- Native: tidak butuh extra tool
- Fast: parallel install + run
- Simple mental model
Con
- No caching: setiap build full
- No task orchestration: run script manual per package
- No project graph: tidak ada visualization dependency
Workflow
# Install semua
bun install
# Run di specific package
bun --cwd apps/api run dev
bun --cwd apps/web run dev
# Or per package script
bun --filter "@my/api" run dev
Cocok untuk 2-5 package, simple shared utility.
Turborepo
Setup
bunx create-turbo@latest
Config:
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"test": {
"dependsOn": ["build"]
}
}
}
Pro
- Build caching: re-build hanya yang berubah (60-90% time saving di typical workflow)
- Remote cache: share cache between team members + CI (via Vercel Remote Cache atau self-host)
- Task orchestration:
turbo run buildcek dependency, run parallel - Less opinionated than Nx: minimal additions to existing project
Con
- Cache management complexity: occasional stale cache issue
- Vendor lock-in to Vercel (sebagian): remote cache via Vercel
- Less powerful than Nx: tidak ada code generation, generator, plugin yang sama deep
Pengalaman
Untuk SaaS billing fotograf (5 package):
- Without Turborepo:
bun run buildsemua = 4-6 menit - Dengan Turborepo (full cache hit):
turbo run build= 8-12 detik - Dengan Turborepo (partial change): 1-3 menit
Game changer untuk team CI workflow.
Nx
Setup
bunx create-nx-workspace@latest
Config kompleks (nx.json, project.json per package, tsconfig.base.json, dll).
Pro
- Full opinionated: scaffolding, generator, plugin
- Powerful project graph: visualize dependency, affected analysis
- Strong caching: comparable to Turborepo + lebih sophisticated
- Plugin ecosystem: Angular, React, Next.js, Astro, NestJS dengan opinionated config
- Affected commands:
nx affected:buildcek what changed, build only impacted
Con
- Steep learning curve: 1-2 minggu untuk fluent
- Over-engineered untuk small project: 2-5 package overkill
- Lock-in to Nx convention: refactor existing project butuh major rework
- Heavy CLI: many command, options
Bila pakai
Worth Nx kalau:
- 15+ package
- Multiple framework (e.g., Next.js + Nest + React Native + Storybook)
- Enterprise team dengan dedicated tooling engineer
- Butuh strict project boundary + code generation
Tidak worth kalau Anda solo dev atau small team — overhead complexity > benefit.
Benchmark
Same task: build 5 package monorepo, full rebuild.
| Tool | Cold | Warm (cache) |
|---|---|---|
| Bun workspaces | 285s | 285s (no cache) |
| Turborepo | 290s (first) | 12s (cache hit) |
| Nx | 320s (first) | 15s (cache hit) |
Cold first build similar. Subsequent build dengan cache: Turborepo + Nx 20-25x faster.
Decision matrix
| Project shape | Recommended |
|---|---|
| 2-5 package, simple monorepo | Bun workspaces |
| 5-20 package, multiple apps | Turborepo |
| 20+ package, multi-framework | Nx |
| Team kecil (1-3 dev), no time for tool overhead | Bun workspaces atau Turborepo |
| Enterprise dengan dedicated tooling team | Nx |
| Migration from polyrepo | Turborepo (gentler) |
Konteks Indonesia
Untuk SMB Indonesia 2026:
- Bun workspaces default untuk most monorepo
- Turborepo worth kalau Anda hit build time pain (CI time > 5 menit consistent)
- Nx hampir tidak relevan untuk SMB
Yang surprising
Saya thought monorepo butuh tool sophisticated. Reality untuk SMB: Bun workspaces sudah cukup untuk 80% use case.
Turborepo shine saat Anda hit CI time pain. Sebelum itu: jangan add complexity.
Nx saya tested 3 hari, lalu bailed. Setup time tidak justify benefit untuk klien saya (3-5 package).
Common pitfall
Shared package versioning: workspace dependency dengan version mismatch silent issue. Pakai workspace:* untuk always link latest local.
Build order: shared package harus build sebelum app. Turborepo/Nx handle via dependsOn. Bun workspaces manual.
CI cache: setup Turborepo remote cache or Nx cloud cache for team. Without ini, cache hanya local — CI miss out.
Circular dependency: monorepo can hide circular import. Run madge --circular regularly.
Verdict
Conditional:
- Default SMB Indonesia: Bun workspaces (simplest, fastest setup)
- Upgrade ke Turborepo saat build time become CI bottleneck
- Nx hanya untuk enterprise scale
Hindari:
- Premature adoption Nx untuk 3-5 package project (over-engineered)
- Migrate dari Bun workspaces tanpa concrete pain point
- Skip caching saat monorepo grow > 10 package
Ditulis oleh Asti Larasati