Qué es Rolldown: el bundler en Rust sobre Oxc
Rolldown es un bundler escrito en Rust y construido sobre Oxc, el compilador que aporta un parser y un AST compartidos a todo el toolchain. Nace para ser el motor unificado de Vite, capaz de reemplazar a la vez a esbuild y a Rollup. Reescribir el bundler desde cero no fue una mejora incremental: rompió el viejo triángulo de compromisos entre velocidad, calidad de salida y ecosistema de plugins.
Durante una década, elegir bundler fue elegir en qué esquina de un triángulo aceptabas perder: velocidad, calidad de salida o ecosistema de plugins. esbuild ofrecía velocidad brutal a cambio de un modelo de plugins limitado; Rollup ofrecía el mejor tree shaking y la API de plugins estándar a cambio de la lentitud de JavaScript. Rolldown es el intento —consumado en 2026— de no elegir: un bundler escrito en Rust, construido sobre el compilador Oxc, con la API de Rollup y la velocidad de un lenguaje compilado. Entender qué es y por qué reescribirlo desde cero cambió las reglas es el punto de partida de todo este nivel.
- Definir Rolldown como un bundler en Rust construido sobre el compilador Oxc.
- Entender por qué los bundlers en JavaScript chocaban contra un techo de rendimiento.
- Ver cómo un único AST compartido convierte “parsear una vez” en la idea central.
- Comprender por qué reescribir el bundler rompió el viejo triángulo de compromisos.
Qué es Rolldown
Rolldown es un bundler: una herramienta que toma tus módulos de entrada, construye el grafo de dependencias, resuelve cada import, transforma el código, elimina lo que no se usa y emite unos pocos artefactos optimizados. Hasta aquí, la misma definición que Rollup o webpack. Lo que lo distingue son dos decisiones de ingeniería. La primera: está escrito en Rust, no en JavaScript. La segunda: no se apoya en un parser propio y aislado, sino en Oxc —el Oxidation Compiler—, una familia de herramientas en Rust que comparten un mismo árbol de sintaxis.
El trabajo que hace por dentro es siempre la misma secuencia, y conviene tenerla presente porque cada etapa es un lugar donde el lenguaje del motor importa:
- Resolver: convierte cada especificador de
importen la ruta real de un archivo, siguiendo el algoritmo de Node y el campoexports. - Cargar y parsear: lee el contenido de cada módulo y lo convierte en un árbol de sintaxis manipulable.
- Transformar: baja TypeScript y JSX a la sintaxis del target y aplica lo que pidan los plugins.
- Empaquetar: une el grafo, aplica el tree shaking y decide el troceado en chunks antes de emitir el código final.
Su propósito no es competir como un bundler más entre muchos, sino ocupar un hueco muy concreto: ser el motor único de Vite. Vite necesitaba históricamente dos motores —esbuild para pre-empaquetar dependencias en desarrollo, Rollup para el build de producción— y Rolldown nace para reemplazar a ambos con una sola pieza. Detrás está VoidZero, la organización fundada por el creador de Vite para construir un toolchain unificado en Rust. Esas piezas no son productos sueltos, sino estratos de una misma decisión de diseño:
- Oxc: el compilador base en Rust —parser, resolver, transformador— que sostiene a todos los demás.
- Rolldown: el bundler que empaqueta el grafo apoyándose en el AST de Oxc.
- Vite: el framework de build que usa Rolldown como motor único en desarrollo y en producción.
- Vitest: el runner de tests que reutiliza la misma tubería de transformación para ejecutar tus pruebas.
// La API basica de Rolldown reproduce deliberadamente la de Rollup
import { rolldown } from 'rolldown'
const bundle = await rolldown({
input: 'src/main.ts',
})
await bundle.write({ dir: 'dist', format: 'esm' })
Que la firma sea casi idéntica a la de Rollup no es casualidad: es la tesis de todo el proyecto. Rolldown cambia el motor por debajo y conserva la interfaz por encima. Ese contraste —motor nuevo, interfaz vieja— es lo que le permite entrar en un ecosistema maduro sin pedirle que se reescriba.
Esa promesa cabe en una línea de import: pasar de rollup a rolldown no debería costarte mucho más que eso. El resto del nivel es, en el fondo, la exploración de hasta dónde se cumple —cuánto se conserva, cuánto se acelera y qué precio, si alguno, pagas por el salto—.
El techo de los bundlers en JavaScript
Un bundler es, en el fondo, un compilador: parsea texto a un árbol, recorre ese árbol muchas veces, lo transforma y vuelve a emitir texto. Ese trabajo es intensivo en CPU y, en su mayor parte, paralelizable: cada módulo del grafo se puede parsear y transformar de forma independiente. JavaScript, sin embargo, arrastra tres lastres estructurales para esa carga, y conviene nombrarlos con precisión porque explican por qué ningún truco de librería los esquiva:
- Un solo hilo: el modelo de ejecución sobre un bucle de eventos hace incómodo repartir el trabajo del grafo entre varios núcleos.
- El recolector de basura: introduce pausas impredecibles justo cuando manipulas millones de nodos de AST.
- Estructuras costosas: objetos, cadenas y cierres pesan mucho más en memoria que los tipos de un lenguaje con control manual.
Cada uno de esos lastres es tolerable en el código de una aplicación, donde el trabajo llega a ráfagas, pero se vuelve dominante en un bundler, donde el mismo patrón se repite decenas de miles de veces sobre un árbol gigante. Ahí es donde la elección de lenguaje deja de ser un detalle de gusto y pasa a ser el factor que fija el suelo de latencia.
esbuild demostró en 2020 lo que estaba en juego: reescrito en Go, un lenguaje compilado con hilos y sin las penalizaciones del intérprete, era cien veces más rápido que los bundlers en JavaScript. La lección fue nítida. El cuello de botella nunca había sido el algoritmo, sino el sustrato: parsear, recorrer y emitir en un lenguaje interpretado tiene un suelo de latencia que ningún truco de JavaScript baja.
El salto de sustrato se puede leer como una escalera de tres peldaños, cada uno más cerca del metal:
- Interpretado, JavaScript: flexible y ubicuo, pero con un suelo de latencia alto y un solo hilo útil.
- Compilado con recolector, Go: cien veces más rápido y con hilos, pero con pausas al manipular árboles enormes.
- Compilado con control manual, Rust: sin pausas y con la memoria gobernada al detalle, el peldaño donde vive Rolldown.
esbuild eligió Go; Rolldown elige Rust. La diferencia importa. Rust no tiene recolector de basura, así que no hay pausas impredecibles al manipular árboles enormes; su control de memoria permite arenas y string interning que reducen las asignaciones intermedias; y su concurrencia sin miedo —el compilador garantiza en tiempo de compilación que no hay carreras de datos— hace realista repartir el grafo entre todos los núcleos. Go es rápido; Rust apura el último orden de magnitud y, sobre todo, comparte lenguaje con Oxc, que ya vivía en Rust.
Un solo AST: por qué reescribir cambió las reglas
La decisión más profunda de Rolldown no es “estar en Rust”, sino apoyarse en Oxc y su AST compartido. En el mundo anterior, cada herramienta reparseaba tu código con su propia gramática: Babel para transformar, el bundler para empaquetar, el linter para analizar, el formateador para reescribir. Cuatro parsers, cuatro árboles, cuatro semánticas que casi coincidían. Oxc rompe esa redundancia: parsea una vez y ofrece ese mismo árbol al resolver, al transformador, al linter oxlint y al bundler Rolldown.
Sobre ese árbol único, Oxc reúne una familia de herramientas que antes eran proyectos separados y sin relación entre sí:
- Un parser entre los más rápidos que existen para JavaScript y TypeScript.
- Un resolver que sigue el algoritmo de Node y el campo
exportsde los paquetes. - Un transformador que baja TypeScript y JSX al target sin depender de Babel.
- Un linter y un formateador,
oxlintyoxfmt, que reutilizan el mismo árbol en lugar de reparsear.
flowchart TD src[Tu codigo fuente] --> oxc[Oxc parsea una sola vez] oxc --> ast[Un AST compartido] ast --> res[Resolver estilo Node] ast --> trans[Transformador TS y JSX] ast --> bundle[Rolldown empaqueta] ast --> lint[oxlint y oxfmt] style oxc fill:#f38ba8,color:#11111b style ast fill:#a6e3a1,color:#11111b style bundle fill:#94e2d5,color:#11111b
De aquí sale la doble ganancia. Velocidad, porque parsear una vez y reutilizar el árbol es más barato que parsearlo cuatro veces con reglas distintas. Y coherencia, porque una sola semántica no puede discrepar consigo misma: la clase entera de bugs que nacía de que dos parsers interpretaran distinto el mismo archivo se extingue en su raíz. Reescribir el bundler no fue, entonces, cambiar una pieza; fue rediseñar el cimiento sobre el que se apoyan todas.
Ese rediseño es lo que rompe el viejo triángulo. Antes tenías que elegir dos vértices de tres: rápido y con buenos plugins pero atado a JavaScript (Rollup), o rapidísimo pero con plugins pobres (esbuild). El triángulo obligaba a renunciar siempre a un vértice:
- Velocidad de lenguaje compilado: la tenía esbuild, pero a costa de un modelo de plugins pobre.
- Calidad de salida con tree shaking serio: la tenía Rollup, atado a la lentitud de JavaScript.
- Ecosistema de plugins maduro: también Rollup, que definió el estándar que todos adoptaron.
Rolldown se planta en el centro: reúne los tres vértices porque el sustrato en Rust y el AST de Oxc disuelven el intercambio que los mantenía separados. La restricción que gobernó una década —“elige rápido o flexible, no ambos”— deja de ser cierta.
En Rust
Sin recolector de basura, con control de memoria y concurrencia sin carreras. El sustrato que rompe el suelo de latencia de JavaScript.
Sobre Oxc
Un parser, un resolver y un transformador que comparten un solo AST. Parsear una vez alimenta bundle, lint y formato.
API de Rollup
La interfaz que el ecosistema ya conoce. Motor nuevo por debajo, contrato viejo por encima: entra sin pedir reescrituras.
De webpack a Rolldown en una década
Rolldown no apareció en el vacío: es el tercer acto de una historia de reescrituras que conviene tener en la cabeza, porque marca la dirección del toolchain entero. Cada acto movió el motor a un sustrato más rápido sin cambiar, en esencia, lo que un bundler hace.
- webpack, en JavaScript: definió el empaquetado moderno —code splitting, carga de assets, HMR— pagando el precio de la lentitud del intérprete.
- esbuild, en Go: probó que un lenguaje compilado bajaba los tiempos cien veces, a cambio de un modelo de plugins y un tree shaking más limitados.
- Rolldown, en Rust sobre Oxc: recupera la calidad y el ecosistema de Rollup a velocidad de lenguaje compilado, con un AST compartido de punta a punta.
La moraleja de esa secuencia es que el algoritmo del empaquetado apenas cambió; lo que cambió, tres veces, fue el motor que lo ejecuta. Quien interiorice esa distinción —problema estable, motor mortal— leerá el resto del nivel con la lente correcta y entenderá por qué el próximo salto, cuando llegue, volverá a conservar la interfaz.
La historia de Rolldown es una lección de arquitectura que trasciende al bundler concreto. Durante años, el ecosistema aceptó como ley natural un triángulo de compromisos: no se podía tener a la vez velocidad de lenguaje compilado, calidad de salida con tree shaking serio y un ecosistema maduro de plugins. Cada herramienta ocupaba una esquina y renunciaba al resto. esbuild eligió velocidad y sacrificó los plugins; Rollup eligió calidad y ecosistema y pagó con la lentitud de JavaScript; webpack eligió flexibilidad y pagó con complejidad y latencia. Rolldown demuestra que ese triángulo no era una ley, sino un artefacto del sustrato. Al mover el motor a Rust y apoyarlo en el AST compartido de Oxc, las tres esquinas dejan de excluirse: la velocidad viene del lenguaje compilado y de parsear una sola vez; la calidad viene de reimplementar el tree shaking de Rollup, no de degradarlo; y el ecosistema sobrevive porque la API de plugins de Rollup se conserva casi intacta. Fíjate en el patrón, porque lo verás repetido en todo el toolchain moderno: no se innova rompiendo la interfaz que la gente usa, sino reemplazando el motor debajo de ella. Quien aprendió la API de Rollup en 2019 no tuvo que reaprender nada en 2026; su conocimiento migró gratis al motor nuevo porque el proyecto tuvo la disciplina de tratar la interfaz como sagrada y el motor como reemplazable. Esa es la moraleja estratégica que debes internalizar: en un mundo donde los motores se reescriben cada pocos años —de webpack a esbuild a Rolldown—, apostar por la interfaz estable en vez del motor de moda es lo que hace que tu conocimiento no caduque. Reescribir el bundler cambió las reglas no porque fuera más rápido, sino porque probó que los compromisos que dábamos por eternos eran solo el precio de un mal sustrato.
- Instala
rolldownen un proyecto vacío y empaqueta unsrc/main.tsmínimo con la API del ejemplo; observa el formato de salida. - Enumera las tres piezas de VoidZero que comparten el cimiento de Oxc y explica qué hace cada una.
- Dibuja el viejo triángulo de compromisos y marca en qué esquina vivían esbuild, Rollup y webpack.
- Explica en dos frases por qué un solo AST compartido reduce a la vez el tiempo de build y la clase de bugs por divergencia de parser.
- Argumenta por qué el cuello de botella de los bundlers en JavaScript era el sustrato y no el algoritmo.