wandres.dev
ELEGIR HERRAMIENTA · Turborepo vs Nx vs Moon

Moon en Rust y el resto del panorama

Mas alla de los dos grandes hay un tercer contendiente serio y un archipielago de nichos. Moon, escrito en Rust, aporta un angulo que ni Turborepo ni Nx tienen de serie: gestiona el propio toolchain, descargando y fijando la version del runtime con proto para que cada maquina y cada CI usen exactamente la misma. Alrededor orbitan Bazel y Buck2 en el extremo hermetico, Rush en el enterprise sobre pnpm, y Wireit o Lage en el minimalismo. Conocer el mapa completo evita elegir un martillo cuando el problema pedia otra herramienta.

⏱ 17 min

El debate de los monorepos suele reducirse a Turborepo contra Nx, pero esa dicotomía deja fuera opciones que resuelven problemas que ninguno de los dos aborda de serie. La más relevante en 2026 es Moon, un build system escrito en Rust que trae un ángulo propio: no solo orquesta tareas, gestiona el toolchain entero, descargando y fijando la versión del runtime para que ni una máquina del equipo ni ningún runner de CI difieran en la versión de node, bun o rust que ejecutan. Más allá de Moon se extiende un archipiélago de herramientas —Bazel y Buck2 en el extremo hermético, Rush en el enterprise, Wireit y Lage en el minimalismo— cada una afilada para un nicho. Conocer el mapa completo es lo que evita elegir por defecto uno de los dos grandes cuando el problema pedía otra pieza.

🎯 Al terminar esta lección sabrás
  • Situar Moon como tercera opción seria y entender su motor en Rust.
  • Comprender la idea de toolchain gestionado y por qué proto la distingue.
  • Recorrer el resto del panorama: Bazel, Buck2, Rush, Wireit y Lage.
  • Mapear cada herramienta a su nicho para no usar la equivocada por inercia.

Moon: un task runner en Rust con más ambición

Moon, del proyecto moonrepo, es un build system escrito en Rust que compite en la misma capa que Turborepo y Nx: descubre proyectos, modela un grafo de dependencias y de tareas, hashea entradas, cachea salidas local y remotamente, y ejecuta solo lo afectado. Hasta aquí, el catálogo es familiar. Su diferencia empieza en cómo define las tareas y en dónde traza sus fronteras.

Frente al modelo de Turborepo —envolver los scripts que ya viven en cada package.json— Moon centraliza la configuración en su propio formato. La configuración global vive en .moon/workspace.yml y .moon/toolchain.yml, y cada proyecto declara sus tareas en un moon.yml. Ese diseño habilita algo que Turborepo no expresa con naturalidad: la herencia de tareas. Defines una tarea una sola vez a nivel global y todos los proyectos que encajan con una etiqueta la heredan, en vez de repetir el mismo script en cincuenta package.json.

# moon.yml de un proyecto: tareas declaradas, no scripts crudos
type: library
language: typescript
tasks:
  build:
    command: tsc --build
    inputs: ["src/**/*"]
    outputs: ["dist"]
moon run ui:build      # ejecuta una tarea de un proyecto
moon run :test         # la tarea test en todos los proyectos que la tengan
moon ci                # ejecuta lo afectado, pensado para pipelines
📝
Moon compite en la capa de tareas, igual que los dos grandes

Como Turborepo y Nx, Moon no reemplaza a pnpm en la capa de workspace: se sienta encima para orquestar. Lo que cambia es la superficie —configuración centralizada en YAML con herencia, en vez de envolver scripts sueltos— y, sobre todo, que Moon extiende su alcance una capa más abajo de lo que los otros dos tocan: el propio runtime.

proto y la idea de toolchain gestionado

El ángulo que de verdad distingue a Moon es que gestiona el toolchain. Turborepo y Nx asumen que node, bun o la herramienta que uses ya están instalados y en la versión correcta; delegan ese problema en corepack, volta o en la disciplina del equipo. Moon lo asume como propio a través de proto, su gestor de versiones universal —también en Rust—: declaras la versión del runtime en la configuración, y Moon la descarga, la fija y la usa, de modo que cada desarrollador y cada CI ejecutan exactamente el mismo binario.

flowchart TD
cfg[toolchain yml declara versiones] --> proto[proto descarga y fija runtime]
proto --> node[node exacto]
proto --> bun[bun exacto]
moon[moon orquesta tareas] --> proto
style proto fill:#cba6f7,color:#11111b
style moon fill:#89b4fa,color:#11111b

Esto ataca una clase entera de fallos que los otros dos dejan a tu cargo: el clásico funciona en mi máquina causado por versiones de runtime divergentes. Si el hash de una tarea no incluye la versión de la herramienta que la ejecuta, dos máquinas con node distinto pueden producir salidas distintas desde entradas idénticas y envenenar la caché. Moon, al gestionar el toolchain, puede incorporar esa versión al hash y garantizar la reproducibilidad de raíz.

# .moon/toolchain.yml: el runtime es parte de la configuracion
node:
  version: "22.14.0"
  packageManager: pnpm
💡
Toolchain gestionado es reproducibilidad por diseño

La diferencia práctica se nota en el onboarding y en el CI. Sin toolchain gestionado, un repo depende de que cada persona instale la versión correcta y de que el runner de CI la clave por su cuenta; cualquier desviación es una fuente silenciosa de builds no reproducibles. Con Moon y proto, la versión es un dato versionado en el repo y aplicado por la herramienta, no una convención que confías en que todos respeten. Es la misma filosofía de la caché por contenido, extendida hasta el runtime.

El resto del panorama, de Bazel a Wireit

Fuera de los tres contendientes de la capa JS hay herramientas afiladas para nichos concretos. Confundir su terreno es la vía rápida a sobredimensionar o a quedarse corto.

🧱

Bazel y Buck2

Builds herméticos y poliglota a mega-escala, con sandboxing y ejecución remota. Linaje de Google y Meta. Potencia enorme a cambio de un coste de adopción que solo se justifica en organizaciones inmensas.

🏢

Rush

De Microsoft, sobre pnpm, orientado al enterprise con builds por fases y políticas estrictas de versiones. Su nicho es la organización grande que quiere gobernanza fuerte sin saltar a Bazel.

🪶

Wireit y Lage

Minimalismo extremo: Wireit, de Google, aumenta los scripts de npm con dependencias y caché sin cambiar el modelo; Lage, de Microsoft, es un runner de pipelines ligero. Para quien quiere casi nada.

🕰️

Lerna y otros

Lerna, histórico, hoy mantenido bajo el paraguas de Nx y reducido casi a versionado y publicación. Pants para el mundo Python. Piezas legacy o de otro ecosistema, no candidatos por defecto en JS.

El eje que ordena todo este archipiélago es el hermetismo. En un extremo, Turborepo confía en tus scripts y no aísla nada; en el otro, Bazel y Buck2 ejecutan cada acción en un sandbox que declara todas sus entradas y salidas, garantizando reproducibilidad absoluta a costa de reescribir cómo se construye cada cosa. Moon y Nx viven en el medio, y Moon empuja hacia el hermetismo justamente al gestionar el toolchain. Elegir en este eje es elegir cuánta reproducibilidad necesitas y cuánto estás dispuesto a pagar por ella.

Herramienta Nicho Rasgo distintivo
Moon monorepos JS que quieren reproducibilidad toolchain gestionado con proto, en Rust
Bazel y Buck2 mega-escala poliglota hermética sandboxing y ejecución remota
Rush enterprise sobre pnpm builds por fases y gobernanza de versiones
Wireit y Lage minimalismo sobre scripts npm caché ligera sin cambiar el modelo
ℹ️
El tercero en discordia no es un capricho, resuelve un hueco real

Moon no existe por moda de reescribir cosas en Rust. Ocupa un hueco genuino entre Turborepo y Nx: más reproducible que el primero por gestionar el runtime, más ligero que el segundo por no imponer una plataforma entera. Si tu dolor concreto es que las versiones de herramientas divergen entre máquinas y envenenan tus builds, Moon lo ataca de frente donde los dos grandes te dejan resolverlo por tu cuenta. No es la opción por defecto, pero para ese dolor específico puede ser la más directa.

El panorama es un espacio de nichos, no un ranking lineal

La forma perezosa de pensar los build systems es como una liga: Turborepo y Nx en primera división, Moon como aspirante, y el resto en categorías inferiores, todos compitiendo por el mismo título de mejor herramienta. Ese modelo es falso y conduce a malas decisiones. Estas herramientas no compiten por un puesto en una escala única; ocupan posiciones distintas en un espacio de varias dimensiones —hermetismo, poliglotismo, gestión del runtime, peso de la plataforma, apetito de configuración— y cada una es óptima en la región que fue diseñada para habitar. Bazel no es Turborepo con esteroides: es una respuesta a un problema —reproducibilidad hermética multi-lenguaje a la escala de una empresa de miles de ingenieros— que Turborepo ni intenta resolver y que, para un repo de veinte paquetes, sería una catástrofe de complejidad. Moon no es un Nx más rápido: es una apuesta distinta sobre dónde trazar la frontera de la herramienta, extendiéndola hasta el toolchain en lugar de hasta los generadores. Wireit no es un Turborepo pobre: es una decisión de hacer aún menos, para quien ni siquiera quiere un archivo de configuración nuevo. Entender el panorama, por tanto, no es memorizar un ranking sino aprender a leer el mapa: qué dimensión importa para tu problema, y qué herramienta es óptima en esa región. La pregunta madura nunca es cuál es el mejor build system, porque no existe tal cosa fuera de un contexto; la pregunta es en qué región del espacio vive mi problema, y qué herramienta fue diseñada precisamente para esa región. Quien domina el mapa elige la pieza afilada para su nicho; quien solo conoce a los dos grandes acaba forzando todo problema a caber en el molde de un martillo que quizá no era el suyo.

⚔️ Ubica tu problema en el mapa del panorama
  1. Instala proto y fija la versión de node de un proyecto; comprueba que la versión queda versionada en el repo y no depende de lo que cada uno tenga instalado.
  2. Monta un moon.yml mínimo con una tarea build y ejecútala con moon run, comparando la ergonomía con envolver un script en Turborepo.
  3. Pregúntate si tu repo sufre divergencias de versión de runtime entre máquinas: si sí, argumenta por qué el toolchain gestionado de Moon te paga.
  4. Sitúa tu proyecto en el eje del hermetismo y justifica por qué Bazel sería exceso o defecto para tu escala actual.
  5. Para cada herramienta del panorama, escribe en una línea el nicho que la haría la elección correcta; el ejercicio te deja el mapa memorizado.