wandres.dev
ROLLDOWN · el bundler en Rust

Rendimiento: por qué es 10-30x más rápido y unifica dos motores

Rolldown logra builds entre 10 y 30 veces más rápidos que Rollup gracias a Rust, al AST compartido de Oxc y al paralelismo entre núcleos. Pero la ganancia decisiva no es la velocidad en sí, sino lo que la velocidad hace posible: fundir en un solo motor lo que Vite repartía entre esbuild en desarrollo y Rollup en producción, y con ello extinguir toda una clase de bugs de paridad dev/build.

⏱ 16 min

La cifra que todos repiten —10 a 30 veces más rápido que Rollup— es real, pero contarla sola es perder de vista lo importante. La velocidad de Rolldown no es un fin, es una llave. Durante años Vite convivió con dos motores porque ninguno servía para las dos fases: esbuild era rápido para pre-empaquetar en desarrollo pero pobre en salida, Rollup era excelente en salida pero lento para el build. Rolldown es lo bastante veloz como para hacer ambos trabajos con una sola pieza, y esa unificación —no el número de benchmark— es la verdadera revolución. Este nivel explica de dónde sale la velocidad y por qué su consecuencia más profunda es la coherencia.

🎯 Al terminar esta lección sabrás
  • Identificar las cuatro fuentes de la velocidad de Rolldown: Rust, Oxc, paralelismo y transforms nativos.
  • Interpretar la cifra 10-30x y entender por qué varía tanto entre proyectos.
  • Comprender cómo un solo motor sustituye a esbuild en dev y a Rollup en build.
  • Ver por qué la velocidad es el medio y la coherencia dev/build es el fin.

De dónde sale la velocidad

La aceleración de Rolldown no viene de un único truco, sino de cuatro decisiones que se refuerzan. La primera es el lenguaje: Rust compila a código nativo, no tiene recolector de basura que pause el proceso al manipular árboles enormes y permite controlar la disposición de la memoria con arenas y string interning que evitan asignaciones intermedias. La segunda es Oxc: su parser está entre los más rápidos que existen para JavaScript y TypeScript, y como el AST se comparte, el código se parsea una sola vez y ese árbol alimenta la resolución, la transformación y el empaquetado en lugar de reparsearse en cada etapa.

La tercera fuente es el paralelismo. El grafo de módulos es, por naturaleza, paralelizable: cada módulo se puede parsear y transformar de forma independiente. Rust hace realista repartir ese trabajo entre todos los núcleos de la máquina porque su sistema de tipos garantiza en tiempo de compilación que no hay carreras de datos —la famosa concurrencia sin miedo—. Un bundler en JavaScript, atado a un solo hilo por el bucle de eventos, no puede aprovechar ocho o dieciséis núcleos para el trabajo pesado; Rolldown sí. La cuarta fuente son las transformaciones nativas: al llevar Oxc dentro, transpila TypeScript y JSX sin salir del núcleo, sin el ida y vuelta a Babel o a un plugin externo que frenaba a Rollup.

En conjunto, la aceleración se apoya en cuatro pilares que se refuerzan entre sí:

  • Lenguaje compilado: Rust ejecuta a código nativo, sin intérprete ni recolector de basura que pause el proceso.
  • Parseo único: el AST compartido de Oxc se calcula una vez y se reutiliza en cada etapa del pipeline.
  • Paralelismo entre núcleos: el grafo se reparte sin carreras de datos gracias al sistema de tipos de Rust.
  • Transforms nativos: TypeScript y JSX se bajan dentro del motor, sin cruzar a un plugin en JavaScript.

Ninguno de los cuatro pilares basta por sí solo; su fuerza está en el refuerzo mutuo. El paralelismo solo rinde si el lenguaje no impone pausas de recolección en mitad del reparto; el parseo único solo ahorra si hay un AST compartido que reutilizar; los transforms nativos solo aceleran si no obligan a cruzar a un runtime interpretado. Rolldown gana no por tener el parser más rápido ni por exprimir más núcleos, sino por alinear las cuatro decisiones en la misma dirección, de modo que cada una potencia a las demás en vez de cancelarlas.

🦀

Rust nativo

Código compilado, sin pausas de recolector de basura, con memoria controlada. El suelo de latencia baja un orden de magnitud.

🌳

Un AST, una vez

Oxc parsea una sola vez y reparte el árbol. No hay cuatro parsers repitiendo el mismo trabajo con reglas casi iguales.

⚙️

Paralelismo real

El grafo se reparte entre todos los núcleos. La concurrencia sin carreras de Rust hace viable lo que un solo hilo no puede.

La cifra 10-30x y sus matices

Decir “10 a 30 veces más rápido” es honesto solo si se explica por qué es un rango y no un número. La aceleración depende del tamaño del grafo y de la mezcla de plugins. En proyectos pequeños, el arranque y la sobrecarga fija pesan más que el empaquetado, así que la ganancia se acerca al extremo bajo. En proyectos grandes —miles de módulos— el paralelismo y el parseo único de Oxc despliegan toda su ventaja, y ahí es donde aparecen los factores más altos: cuanto más grande el grafo, más trabajo hay que repartir entre núcleos y más se nota no reparsear.

# Un build de produccion sobre un grafo grande, comparado
# Rollup en JavaScript, un solo hilo
time rollup -c        # decenas de segundos

# Rolldown en Rust, repartido entre nucleos
time rolldown -c      # unos pocos segundos

El factor concreto que verás depende de varias variables que conviene tener presentes al interpretarlo:

  • El tamaño del grafo: más módulos significan más trabajo paralelizable y más ventaja.
  • El número de núcleos: cuantos más tenga la máquina, más se reparte el trabajo pesado.
  • La fracción en plugins de JavaScript: cuanto mayor sea, menos acelera el conjunto.
  • El estado del caché: un caché frío mide el motor; uno caliente mide otra cosa.

La mezcla de plugins también modula la cifra. Un build dominado por hooks de plugins escritos en JavaScript pasa buena parte del tiempo cruzando la frontera hacia el runtime de JavaScript, y esa parte no acelera tanto como el núcleo en Rust; por eso los filtros de hooks y los plugins nativos que viste en el nivel anterior importan tanto para el rendimiento real. Hay una ley vieja detrás de esto: la aceleración total está acotada por la fracción del trabajo que no aceleras. Si la mitad de tu build se va en plugins de JavaScript, ni un motor infinitamente rápido en Rust bajaría esa mitad, así que el techo de tu mejora lo fija la parte que sigue en el runtime interpretado. La lectura correcta de la cifra es esta: no es una constante mágica, es el resultado de mover a Rust y paralelizar la parte del trabajo que antes hacía JavaScript en un solo hilo, y su magnitud crece con lo que haya de esa parte.

💡
Mide en tu proyecto, no en el benchmark ajeno

La cifra que te importa no es la del anuncio, sino la de tu repositorio. Antes de migrar, cronometra tu build actual y guárdalo como línea base. Después de adoptar Rolldown, vuelve a medir con la misma máquina y el mismo caché frío. La diferencia real dependerá de cuántos módulos tengas, cuántos núcleos tenga tu máquina y qué fracción del tiempo se iba en plugins de JavaScript. Un proyecto de biblioteca pequeño verá menos; un monorepo con miles de módulos verá el extremo alto del rango.

Unificar dos motores en uno

Aquí está el corazón del nivel. La razón por la que Vite necesitaba dos motores era que ninguno cumplía las dos exigencias a la vez. En desarrollo hacía falta velocidad para pre-empaquetar node_modules con optimizeDeps y transpilar al vuelo, y esa corona la tenía esbuild. En producción hacía falta calidad de salida —tree shaking fino, code splitting exacto— y un ecosistema de plugins maduro, y esa corona la tenía Rollup. Vite cosió ambos: la velocidad de uno en dev, la madurez del otro en build. El precio fue una costura: dos parsers, dos semánticas y una frontera donde anidaban los bugs de “en dev funcionaba y en build no”.

Antes de Rolldown, el reparto entre los dos motores era nítido, y cada uno cargaba con tareas que el otro no podía asumir:

  • esbuild, en dev: pre-empaquetaba node_modules con optimizeDeps y transpilaba TypeScript y JSX al vuelo.
  • esbuild, además: convertía CommonJS a ESM para que el navegador cargara dependencias antiguas.
  • Rollup, en build: resolvía el grafo completo, aplicaba el tree shaking y decidía el troceado en chunks.
  • Rollup, también: ejecutaba la cadena de plugins que daba forma final al artefacto de producción.

Ese reparto tenía una lógica impecable en su momento, pero también un coste oculto: cada motor imponía su propio parser y su propia semántica, de modo que el mismo archivo podía leerse de dos maneras según la fase. La virtud de repartir el trabajo por especialización se pagaba con una frontera donde esas dos lecturas podían discrepar, y ahí anidaban los bugs.

Rolldown disuelve esa costura porque es simultáneamente rápido y de alta calidad. Es lo bastante veloz para hacer el trabajo de esbuild en el pre-empaquetado de dependencias, y lo bastante bueno en salida para hacer el trabajo de Rollup en el build. Por primera vez, dev y build recorren el mismo motor, con el mismo parser y la misma semántica. La velocidad no era el objetivo: era la condición necesaria para que un solo motor pudiera cubrir las dos fases sin ceder en ninguna.

Merece la pena recordar de dónde venimos para medir el cambio. Durante años, el vite dev era instantáneo gracias a esbuild, pero el vite build heredaba la lentitud de Rollup en JavaScript, y en proyectos grandes esa asimetría dolía: un desarrollo rapidísimo y un build comparativamente pesado, con una tierra de nadie entre ambos. Rolldown cierra esa brecha extendiendo la velocidad de un lenguaje compilado también a la fase que Rollup cubría, de modo que el build deja de ser el pariente lento del pipeline y se acerca a la latencia que el dev ya disfrutaba.

flowchart TB
subgraph Antes
  dev1[Dev con esbuild rapido] --> costura[Dos parsers y dos semanticas]
  build1[Build con Rollup de calidad] --> costura
end
subgraph Ahora
  rolldown[Rolldown rapido y de calidad] --> uno[Un motor en dev y en build]
end
costura --> bugs[Bugs de paridad dev y build]
style dev1 fill:#f9e2af,color:#11111b
style build1 fill:#cba6f7,color:#11111b
style rolldown fill:#94e2d5,color:#11111b
style bugs fill:#f38ba8,color:#11111b
style uno fill:#a6e3a1,color:#11111b

Con un solo motor se extingue una familia entera de discrepancias que antes vivían en la frontera entre esbuild y Rollup:

  • Plugins que se comportaban distinto según los ejecutara esbuild en dev o Rollup en build.
  • Sintaxis reciente que un motor sabía leer y el otro todavía no.
  • Helpers de transpilación inyectados con una forma en dev y otra en build.
  • Interoperabilidad CommonJS y ESM resuelta de un modo al servir y de otro al empaquetar.

La consecuencia va más allá de compilar más rápido. Un motor único abre además una posibilidad antes impensable: empaquetar también en desarrollo, el modo de bundle completo. Con Rollup habría sido demasiado lento para hacerlo en cada guardado; con Rolldown, empaquetar es tan barato que dev puede acercarse al comportamiento de producción cuando quieres fidelidad, sin cambiar de herramienta. La velocidad, otra vez, no como fin, sino como llave que abre la coherencia.

Dónde no acelera tanto

Un análisis honesto del rendimiento incluye sus límites. La aceleración de Rolldown ataca el trabajo de CPU del empaquetado, pero no todo el tiempo de un build es ese trabajo, y hay zonas donde el factor se aplana.

  • Plugins en JavaScript: el tiempo que se va en hooks de terceros cruza a un runtime interpretado y no hereda la velocidad del núcleo en Rust.
  • Proyectos pequeños: cuando el grafo es diminuto, la sobrecarga fija de arranque pesa más que el empaquetado y la ganancia se estrecha.
  • Trabajo de entrada y salida: leer y escribir muchos archivos está limitado por el almacenamiento, no por el motor.
  • Pocos núcleos: en una máquina modesta, el paralelismo tiene menos margen que desplegar.

Nada de esto contradice la cifra 10-30x; la sitúa. La aceleración es real y grande donde el trabajo es CPU sobre un grafo grande y paralelizable, que es justo el caso que domina en los proyectos serios. Saber dónde no acelera tanto es lo que separa medir con criterio de repetir un eslogan.

La velocidad es el medio; la coherencia es el premio

Es tentador contar la historia de Rolldown como una carrera de números —cien veces esbuild sobre webpack, treinta veces Rolldown sobre Rollup— y quedarse en la epopeya del rendimiento. Sería quedarse en la superficie. La velocidad de Rolldown importa sobre todo por lo que habilita, no por lo que es. Durante toda la historia de Vite hubo una grieta estructural: dev y build corrían sobre motores distintos porque no existía uno que fuera a la vez rápido para servir y bueno para empaquetar. Esa grieta no era un fallo de nadie, era la consecuencia física de repartir virtudes entre dos herramientas, y de ella brotaba una clase entera de bugs —los de “en mi máquina funcionaba”— que ninguna disciplina eliminaba del todo, porque nacían de que dos parsers veían tu código con reglas ligeramente distintas. Lo que hace Rolldown es cerrar esa grieta en su origen material: al ser lo bastante veloz para cubrir la fase de esbuild y lo bastante bueno para cubrir la de Rollup, permite que un único motor recorra dev y build, con un solo AST y una sola semántica. Y aquí está la inversión conceptual que debes llevarte: la velocidad no resolvió el problema de la lentitud, resolvió el problema de la incoherencia. Sin la velocidad de Rust, unificar los dos motores habría significado que dev heredara la lentitud de Rollup o que build heredara la pobreza de esbuild; con ella, la unificación no exige sacrificar nada, y por eso es posible. Piensa en la jerarquía correcta cuando evalúes cualquier herramienta de build: la latencia baja mejora tu día, pero la coherencia entre lo que pruebas y lo que despliegas mejora tu producto, porque extingue bugs en vez de solo ahorrarte segundos. Rolldown es rápido, sí; pero su regalo duradero es que, por ser rápido, pudo volver a coser en uno lo que durante una década estuvo condenado a vivir en dos.

⚔️ Mide y entiende la aceleración
  1. Cronometra el build de un proyecto real con Rollup y con Rolldown en la misma máquina y registra el factor de aceleración.
  2. Repite en un proyecto pequeño y en uno grande, y explica por qué el factor cambia con el tamaño del grafo.
  3. Cuenta los núcleos de tu máquina y razona qué parte de la ganancia viene del paralelismo y qué parte del lenguaje.
  4. Identifica en tu build qué plugins están escritos en JavaScript y por qué frenan la aceleración teórica.
  5. Argumenta en tres frases por qué la velocidad de Rolldown es la condición que hace posible unificar esbuild y Rollup en un solo motor.