Nx Cloud: Replay y DTE
Nx Cloud lleva la caché y la ejecución más allá de una máquina. Replay es la caché remota: el trabajo que alguien computó una vez se replica en milisegundos en cualquier otra máquina con el mismo hash. DTE reparte las tareas afectadas entre varios agentes según el task graph y los tiempos históricos, minimizando el tiempo total. Y la caché se aísla por rama para impedir el envenenamiento.
La caché local ya evita repetir tu propio trabajo, pero el trabajo de tu equipo sigue multiplicándose: cada persona y cada máquina de CI recomputan por su cuenta lo que otra ya calculó. Nx Cloud rompe esa barrera con dos mecanismos. Replay es la caché remota: un resultado computado una vez se replica en milisegundos en cualquier máquina que pida el mismo hash. DTE —ejecución distribuida de tareas— reparte las tareas afectadas entre varios agentes según el grafo y los tiempos históricos. Juntos convierten “no compilar” de una optimización local en una propiedad de todo el equipo.
- Entender Replay como caché remota y el flujo de acierto y fallo entre máquinas.
- Comprender DTE: repartir tareas entre agentes según el task graph y tiempos históricos.
- Ver el papel del orquestador y los agentes en una ejecución distribuida.
- Entender el aislamiento de caché por rama y por qué previene el envenenamiento.
Replay: la caché remota compartida
Recuerda cómo funciona la caché local: Nx calcula un hash de los inputs de una tarea, y si ya vio ese hash, restaura los outputs en vez de recomputar. Replay es exactamente eso, pero con el almacén de la caché en la nube en lugar de en tu disco. El hash es idéntico —depende de los inputs, no de la máquina—, así que un resultado calculado por una persona puede replicarlo cualquier otra, o cualquier máquina de CI, sin volver a ejecutar la tarea.
El flujo es simple y radical en sus efectos. La primera vez que se ejecuta una tarea con un hash dado, su resultado se sube al almacén remoto. A partir de ahí, cualquier ejecución posterior con ese mismo hash —en el portátil de otra persona, en un runner de CI distinto— es un acierto remoto: Nx descarga los outputs y reimprime la salida de terminal en milisegundos.
flowchart TD A[dev construye ui] --> H1[hash abc] H1 --> S[almacen remoto Nx Cloud] CI[CI necesita ui] --> H2[hash abc] H2 --> S S -->|acierto| R[descarga outputs sin recomputar] style S fill:#cba6f7,color:#11111b style R fill:#a6e3a1,color:#11111b
El efecto compuesto es enorme. En un equipo, la mayoría de las tareas que un CI necesita ya las computó alguien: la persona que abrió el PR, el CI de la rama base, un compañero que trabajó en la misma librería esa mañana. Un pipeline que recomputaba todo desde cero pasa a descargar casi todo y ejecutar solo lo genuinamente nuevo. El build más rápido sigue siendo el que no ocurre, y Replay hace que no ocurra para todo el equipo a la vez.
Conectar un repositorio a la caché remota es un solo comando, y a partir de ahí la caché local y la remota trabajan en capas: Nx consulta primero la local, luego la remota, y solo si ninguna tiene el hash ejecuta la tarea de verdad.
# Conecta el workspace a Nx Cloud y habilita Replay
nx connect
| Aspecto | Caché local | Replay remota |
|---|---|---|
| Dónde vive | tu disco | almacen en la nube |
| Quién la aprovecha | solo tu máquina | todo el equipo y el CI |
| Clave | hash de inputs | el mismo hash de inputs |
| Primer uso | ejecuta y guarda | ejecuta, guarda y sube |
La igualdad de la clave entre ambas capas es lo que hace coherente al sistema: una tarea no distingue si su resultado vino del disco o de la nube, porque su identidad es el hash de sus entradas y ese hash es el mismo en todas partes.
Qué viaja en un acierto
Un acierto no restaura solo los archivos de salida: también reimprime la salida de terminal original, con sus logs y su código de retorno, para que la ejecución sea indistinguible de haber corrido la tarea de verdad. Por eso un acierto remoto se ve así, con la marca de que el resultado se recuperó de la nube.
> nx run ui:build [remote cache]
Nx replayed the output of ui:build from Nx Cloud
NX Successfully ran target build for project ui (12ms)
Los milisegundos delatan que no hubo trabajo real: bajar un artefacto y volcar un log es órdenes de magnitud más barato que compilar. Multiplicado por cientos de tareas en un CI, ese ahorro es lo que convierte veinte minutos en veinte segundos.
La clave de caché: qué entra en el hash
Que Replay sea correcto depende por entero de que el hash identifique de verdad a la tarea. Nx lo calcula a partir de todo lo que puede cambiar el resultado: los archivos fuente del proyecto y de sus dependencias, las opciones del target, las versiones de las dependencias externas, ciertas variables de entorno y la propia versión de Nx. Dos ejecuciones con el mismo hash son la misma tarea, en cualquier máquina del mundo.
Esto vuelve crítica, a escala de equipo, la disciplina de los inputs del nivel anterior. Un input olvidado en tu máquina solo te afecta a ti; el mismo input olvidado con caché remota propaga un resultado obsoleto a todo el equipo y al CI, porque todos comparten el mismo almacén indexado por ese hash incompleto. La caché remota amplifica por igual los aciertos de modelado y los errores.
DTE: repartir el trabajo entre máquinas
Replay elimina el trabajo repetido, pero el trabajo nuevo —lo genuinamente afectado por un cambio grande— aún hay que hacerlo. La respuesta ingenua es una máquina de CI potente que lo corra todo en paralelo, pero una sola máquina tiene un techo de núcleos y de memoria. DTE, la ejecución distribuida de tareas, rompe ese techo repartiendo las tareas entre varias máquinas, los agentes.
La clave es que DTE no reparte al azar ni a partes iguales. Un orquestador lee el task graph y asigna tareas a agentes respetando dos restricciones. Primero, el orden del grafo: una tarea no puede empezar en un agente hasta que sus dependencias hayan terminado, quizá en otro agente distinto. Segundo, los tiempos históricos: Nx Cloud recuerda cuánto tardó cada tarea en ejecuciones previas y usa esa información para equilibrar la carga, de modo que ningún agente quede ocioso mientras otro arrastra la tarea más lenta. El objetivo es minimizar el makespan: el tiempo total hasta que la última tarea termina.
flowchart TD O[orquestador lee el task graph] --> A1[agente 1] O --> A2[agente 2] O --> A3[agente 3] A1 --> C[cache remota compartida] A2 --> C A3 --> C style O fill:#cba6f7,color:#11111b style C fill:#89b4fa,color:#11111b
Aquí Replay y DTE se entrelazan. Cuando el agente 1 termina de construir util, sube su output a la caché remota; el agente 2, que necesita util para construir ui, lo descarga en vez de reconstruirlo. La caché compartida es el canal por el que los agentes intercambian resultados sin coordinarse directamente. Sin ella, la distribución obligaría a recomputar dependencias en cada máquina; con ella, cada tarea se computa una sola vez en todo el sistema.
Cómo se ve en el CI
En la práctica, la distribución se activa con una línea al inicio del pipeline. El comando nx-cloud start-ci-run le dice a Nx Cloud cuántos agentes usar y de qué tipo; a partir de ahí, tus nx affected habituales se ejecutan distribuidos de forma transparente, sin que el resto del pipeline cambie.
# Al inicio del pipeline: declara la ejecucion distribuida
nx-cloud start-ci-run --distribute-on="8 linux-medium-js"
# Tus comandos de siempre, ahora repartidos entre los agentes
nx affected -t lint test build
La cadena 8 linux-medium-js pide ocho agentes de un tipo dado; el orquestador los aprovisiona, les reparte las tareas afectadas según el grafo y los tiempos históricos, y los apaga al terminar. No gestionas máquinas: declaras cuántas quieres y de qué tamaño, y la plataforma se encarga del resto.
La virtud del enfoque de Nx Cloud es que el número de agentes puede ajustarse dinámicamente a la magnitud del PR. Un cambio pequeño que afecta a tres proyectos no necesita veinte máquinas; un cambio en una librería base que afecta a doscientos sí. Repartir según el grafo real de lo afectado, y no según una configuración fija, es lo que evita pagar por veinte agentes cuando dos habrían bastado, y lo que evita ahogar dos agentes cuando hacían falta veinte.
Lo que distingue a DTE de un simple reparto en paralelo es el uso de la historia. Nx Cloud registra cuánto tardó cada tarea en ejecuciones anteriores y usa esos tiempos para decidir el reparto: agrupa las cortas, adelanta las largas y equilibra la carga de modo que todos los agentes terminen a la vez. Un reparto ciego dejaría a un agente arrastrando la tarea más lenta mientras los demás esperan ociosos; el reparto informado por tiempos históricos aplana esa cola.
Repartir muchas tareas entre varias máquinas es fácil; repartirlas para minimizar el tiempo total es un problema de planificación con dependencias, y ahí es donde el grafo y los tiempos históricos ganan al azar. Dos restricciones lo gobiernan a la vez: una tarea no puede empezar antes que sus dependencias, y conviene que la suma de trabajo por agente sea pareja. Resolver ambas es lo que separa un CI que escala casi linealmente con los agentes de uno que añade máquinas sin apenas bajar el reloj.
Aislamiento por rama y seguridad
Una caché compartida y escribible por muchos es también una superficie de ataque. Si cualquier ejecución pudiera escribir en la misma caché que consume una rama protegida, un artefacto malicioso o simplemente corrupto, subido desde una rama cualquiera, podría replicarse hacia main con su hash y ser servido como bueno. Eso es el envenenamiento de caché, y el CVE conocido como CREEP en 2025 demostró que no es una amenaza teórica.
La defensa de Nx Cloud es aislar la caché por rama —branch-scoped—. Los resultados producidos en el contexto de una rama no se replican indiscriminadamente hacia otras; el acceso de escritura a los ámbitos protegidos se controla, de modo que un PR desde un fork pueda leer la caché base para acelerarse pero no escribir en el ámbito que alimenta a la rama principal. La caché deja de ser un bien común indiferenciado y pasa a ser un conjunto de ámbitos con permisos, donde el resultado que consumes proviene de un origen en el que confías.
El modelo de permisos separa dos derechos que antes iban juntos: leer de la caché y escribir en ella. Una rama sin privilegios —un PR desde un fork, código que aún nadie revisó— puede leer los resultados de la base para acelerarse, pero no depositar artefactos en el ámbito que consumen las ramas protegidas. Acelerar el trabajo no revisado deja así de implicar darle permiso para escribir en lo que la producción ejecutará.
Conviene mirar de frente por qué esto importa tanto. El output de una tarea de build no es un dato inerte: es código y artefactos que otras máquinas van a ejecutar. Si un atacante logra colar un output manipulado bajo el hash de una dependencia legítima, no está corrompiendo un archivo, está logrando ejecución de código en cada máquina que replique esa entrada, incluidos los servidores de CI que despliegan a producción. Por eso el aislamiento por rama no es una comodidad organizativa sino un control de seguridad de primer orden: convierte la caché de un canal por el que podría propagarse una intrusión en un almacén con confianza acotada. Al evaluar cualquier sistema de caché remota, la pregunta correcta no es solo cuánto acelera, sino quién puede escribir en lo que tú vas a ejecutar.
Replay
Caché remota: un resultado se computa una vez y se replica en milisegundos en cualquier máquina que pida el mismo hash de inputs.
DTE
Reparte las tareas afectadas entre varios agentes según el task graph y los tiempos históricos, para minimizar el tiempo total.
Aislamiento por rama
Acota quién puede escribir en cada ámbito de la caché, para que compartir resultados no signifique confiar a ciegas.
La jerarquía de optimización del build tiene una cima incómoda de aceptar para quien lleva años persiguiendo compiladores más rápidos: por debajo de cierto punto, la manera de ir más rápido deja de ser computar mejor y pasa a ser no computar. Nx Cloud lleva ese principio a su conclusión lógica en dos dimensiones. En el eje del tiempo, Replay garantiza que cualquier resultado se compute una sola vez en la historia del equipo, no una vez por persona ni una vez por ejecución de CI; el trabajo se vuelve un bien que se produce una vez y se consume infinitas. En el eje del espacio, DTE reparte lo que sí hay que computar entre tantas máquinas como el grafo permita paralelizar, usando los tiempos históricos para que el reparto sea óptimo y no meramente equitativo. La combinación es más que la suma: la caché compartida es precisamente lo que hace barata la distribución, porque los agentes no reconstruyen las dependencias que otros ya calcularon, sino que las descargan. Pero la lección más madura de este nivel no es la velocidad, es la advertencia que la acompaña. Una caché compartida es, por su propia naturaleza, un almacén de código que muchos escriben y muchos ejecutan, y eso la convierte en un vector de ataque de primer orden en cuanto crece el número de contribuyentes. Por eso el aislamiento por rama no es un detalle de configuración sino la condición que vuelve segura toda la arquitectura: sin él, cuanto más comparte el equipo la caché, más expuesto queda; con él, compartir deja de implicar confiar ciegamente. La forma definitiva de la optimización del build en 2026 no es solo no compilar, sino no compilar de un modo que no puedas envenenar.
- Conecta un repositorio a Nx Cloud, ejecuta un
buildcompleto y observa cómo se suben los resultados al almacén remoto. - Borra tu caché local, vuelve a ejecutar el mismo
buildy confirma que ahora es un acierto remoto descargado, no una recomputación. - Configura una ejecución con varios agentes y observa en el panel cómo el orquestador reparte las tareas entre ellos según el grafo.
- Provoca un cambio en una librería base y compara cuántos agentes se activan frente a un cambio en una hoja aislada.
- Investiga la configuración de permisos de la caché de tu organización y verifica que un PR desde un fork puede leer pero no escribir en el ámbito protegido.