Resumen El storytelling con datos es crucial para asegurar que los productos de datos lleven a una...
Buenas prácticas con rv: El gestor de paquetes de R
Introducción
En este post revisaremos y comentaremos sobre el gestor de paquetes de R: rv. La intención es abordar su filosofía de diseño, y las características que lo resaltan como una de las mejores opciones para el manejo de dependencias de R.
Visualiza estas dos metáforas sobre dos escenarios posibles al preámbulo de la preparación de un platillo.
En el primer escenario tu vas a preparar un platillo y cuentas con un ayudante de cocina. Con la receta en mano él se encargará de todos los insumos necesarios para la preparación. Antes de ir a los negocios de abastecimiento, indicados por ti, él se sienta con la receta completa y hace una lista maestra con todos los ingredientes, cantidades exactas, marca específica y en qué negocios de abastecimiento debe conseguir cada uno. Cuando el ayudante de cocina llega a los negocios de abastecimiento, ya sabe exactamente qué comprar y dónde: entra, recoge todo de una vez, y sale. El platillo estará garantizado porque tu ayudante de cocina resolvió todos los conflictos posibles antes de comprar el primer ingrediente. Además, si en el transcurso de la preparación del platillo requieres otro ingrediente, él se encargará de conseguirlo y verificar que empate con el resto que ya tienes.
Pasemos al segundo escenario. Aquí también cuentas con un ayudante de cocina, pero la forma de trabajar es distinta. El proceder es el siguiente: tú le indicas el ingrediente que necesitas y dónde adquirirlo, él va y consigue el primer ingrediente, luego recuerdas que necesitas el segundo, él va y lo busca — pero ese negocios de abastecimiento solo tiene una variedad diferente a la que esperabas, y esa variedad resulta ser incompatible con el primer ingrediente que ya compraste. Entonces debes cambiar el primero para indicarle qué ingredientes debe adquirir y que ambos sean compatibles, después lo mandas a buscar el tercero... y así sucesivamente. Puede que al final el platillo salga, pero el resultado depende del orden en que tú diste las instrucciones y tu ayudante de cocina recorrió los negocios de abastecimiento, y si él regresa mañana, los puestos podrían tener variedades distintas y el platillo quedaría diferente.
Síntesis de la primera metáfora: tú le indicas a tu ayudante de cocina, mediante una receta maestra, qué es lo que necesitas para la preparación del alimento y él se encargá. Tu receta es reproducible porque sabes exactamente qué necesitas, en qué variedad lo quieres y dónde conseguirlo.
Síntesis de la segunda metáfora: tu ayudante de cocina procede con acciones puntuales, no alcanza a ver todo el panorama, al final obtendrás el platillo, pero será más complicado replicarlo y quedará diferente cada vez, y si la variedad de los ingredientes no coincide debes reconfigurar la receta. Además, los negocios de abastecimiento no te consultan cuándo cambian su inventario — mañana podrían tener una variedad distinta del mismo ingrediente, o dejar de tener uno por completo, sin previo aviso. Esto significa que aunque tu ayudante regrese a los mismos negocios con las mismas instrucciones, no hay garantía de que consiga exactamente lo mismo que la vez anterior.
rv
Lo que describimos a manera de metáfora líneas arriba son dos formas de proceder, dos filosofías para manejar y gestionar paquetes en R. La primera, declarativa, se expresan objetivos de alto nivel o se describen restricciones importantes, y se confía en que otro decida cómo y/o cuándo traducir eso en acciones (Wickham, 2021). Y eso, es precisamente la descripción de uno de los ejes centrales de rv.
¿Y qué es rv?
Es un gestor de paquetes de R, escrito en Rust, para ayudar a los usuarios a instalar y gestionar paquetes de R de forma declarativa, reproducible y rápida. (A2-Ai, n.d.)
Permitiéndote:
- Instalar un conjunto coherente de paquetes, asegurándose de que cada uno sea compatible con los demás en el proyecto.
- Especificar opciones para paquetes individuales, incluido de qué repositorio deben obtenerse, si se debe instalar la versión fuente o binaria, si se deben instalar los paquetes sugeridos y mucho más.
- Comprender cómo cambiará el entorno del paquete de su proyecto antes de realizar cualquier instalación.
Por otra parte, la segunda metáfora hace alusión a renv, también un gestor de paquetes de R, pero diferente en su proceder. Con renv, se llega a un estado final mediante un proceso iterativo por medio de ejecución de acciones específicas; los ajustes y solución de conflictos de las versiones de las dependencias se ejecutan en la marcha. Resultado, un producto finalizado pero con dificultad en su reproducibilidad precisa.
El archivo central de configuración (la receta maestra)
Dentro de tu proyecto, el uso de rv se vería como en la siguiente imagen:

Y uno de los objetos diferenciadores de rv que aportan el valor añadido, es precisamente el archivo central de configuración, rproject.toml. Análogo al archivo de configuración del gestor de paquetes uv para Python o Cargo para Rust, el archivo central de configuración se asemeja a una receta maestra con las especificaciones precisas de cada dependencia necesaria. Aquí declaramos qué necesitamos y dónde conseguirlo, rv toma esa declaración, calcula el árbol completo de todas las dependencias de todos los paquetes al mismo tiempo, y determina de una sola vez qué versión de cada paquete satisface todo simultáneamente, no hay pasos intermedios inconsistentes. Además, lo anterior garantiza que el proyecto se encuentre en un estado resoluble, reproducible y consistente.
El rproject.toml
El rproject.toml se estructura en tres elementos principales que definen el estado deseado del proyecto:
- r_version: especifica la versión de R para la cual se instalarán los paquetes. Determina qué versiones de paquetes están disponibles en los repositorios configurados para esa versión específica de R.
- repositories: define la lista de repositorios tipo CRAN desde donde rv obtendrá los paquetes. El orden importa: rv busca cada paquete en los repositorios de arriba hacia abajo, y usa la primera versión resoluble que encuentra. Esto permite un control preciso sobre las fuentes de los paquetes: repositorios internos de la organización, snapshots con fecha fija para reproducibilidad, o repositorios especializados.
- dependencies: es la lista de paquetes que el proyecto necesita. Es el elemento más editado del archivo y el equivalente directo a los ingredientes de nuestra receta maestra. Cada dependencia puede especificarse de forma simple (solo el nombre del paquete) o con opciones adicionales como el repositorio de origen o si debe instalarse desde código fuente.
Ejemplo de archivo de configuración:

El archivo de bloqueo: rv.lock
Si el rproject.toml es la receta maestra, el rv.lock es el registro de compras: documenta con precisión absoluta qué se instaló, en qué versión, de qué repositorio y de qué forma. Por defecto, rv usa un lockfile para asegurar que los paquetes se obtengan del mismo lugar, con la misma versión, en cada instalación.
La diferencia con el enfoque de renv es fundamental: mientras que renv::snapshot() fotografía retroactivamente lo que ya está instalado, rv genera el lockfile como parte del proceso de resolución, antes de instalar el primer paquete. Esto significa que el lockfile de rv no es una observación del resultado, sino un plan del proceso completo.
El rv.lock es el archivo que debe versionarse con Git junto al rproject.toml: los dos juntos garantizan que cualquier colaborador, en cualquier máquina, en cualquier momento, pueda reproducir exactamente el mismo entorno.
rv como herramienta de línea de comandos (CLI)
rv opera principalmente desde la terminal, con comandos que reflejan su filosofía declarativa: no se le indica qué hacer paso a paso, sino que se le describe el estado deseado y él determina cómo llegar ahí. Te presento tres de sus principales comandos:
rv init
El punto de entrada para cualquier proyecto nuevo. Al ejecutar rv init en una carpeta, rv realiza dos acciones:
- Configura la infraestructura del proyecto: la librería local (rv/library/) y los scripts de activación (activate.R, rvr.R) que garantizan que cada sesión de R arranque con el entorno correcto.
- Crea el rproject.toml poblado automáticamente con la versión de R detectada en el sistema y los repositorios disponibles.
rv sync
Es el comando central de trabajo diario. Sincroniza el rproject.toml, el rv.lock y la librería del proyecto, agregando o eliminando dependencias según sea necesario para alcanzar el estado deseado declarado en la configuración. rv sync calcula el árbol completo de dependencias, resuelve todo de una vez, y ejecuta solo los cambios necesarios para llevar el proyecto al estado correcto.
Migración desde renv: rv migrate renv
Para proyectos que ya usan renv, rv ofrece un camino de migración directo. El comando rv migrate renv realiza dos pasos:
- Configura la infraestructura del proyecto de rv (librería y scripts de activación), de forma idéntica a rv init.
- Traduce el renv.lock existente a un rproject.toml de rv, migrando las dependencias y repositorios registrados.
Vale la pena señalar la honestidad de la documentación oficial en este punto: no se puede garantizar que rv migrará el proyecto renv en su totalidad. Esto es especialmente relevante para dependencias que en renv venían de fuentes no estándar (GitHub, repositorios privados), donde la información de origen puede no haberse capturado con suficiente precisión en el renv.lock; posible consecuencia directa de las limitaciones del snapshot retroactivo que ya discutimos.
Buenas prácticas
Las buenas prácticas que rv promueve por diseño son:
- Declarar antes de instalar: el rproject.toml obliga a pensar en el entorno completo del proyecto antes de ejecutar cualquier instalación.
- Versionar siempre rproject.toml y rv.lock juntos: los dos archivos son inseparables: el primero declara la intención, el segundo la garantiza. Sin ambos en el repositorio de Git, la reproducibilidad es parcial.
- Controlar las fuentes explícitamente: definir repositorios con alias y orden preciso elimina la ambigüedad sobre de dónde viene cada paquete.
- Separar la librería del proyecto del sistema: cada proyecto tiene su propio rv/library/, aislado de la librería del sistema y de otros proyectos, eliminando la clase de conflictos que describimos en la metáfora del segundo escenario.
- Tratar el entorno como código: rv refuerza la práctica de que el entorno de un proyecto no es algo que se construye una vez de forma manual, sino algo que se declara, se versiona y se reproduce; con la misma rigurosidad con la que se trata el código fuente del proyecto.
Conclusión
rv no es simplemente otra herramienta para instalar paquetes de R, es un cambio de paradigma en la forma de pensar la gestión de dependencias dentro de R.
La diferencia central con renv no es técnica sino filosófica. renv adopta el modelo imperativo e iterativo: se instala, se ajusta, se vuelve a instalar, y al final se fotografía el resultado con un snapshot. Es un proceso que avanza hacia el estado correcto, pero sin visión completa del destino. rv invierte ese orden: primero se declara el estado deseado en su totalidad, luego se resuelve el árbol completo de dependencias de una sola vez, y solo entonces se instala; con la certeza de que el resultado será coherente, reproducible y verificable. Como vimos en nuestra metáfora, la diferencia entre un ayudante de cocina que sale al mercado con una lista maestra resuelta de antemano, y uno que va ingrediente por ingrediente sin ver el panorama completo.
Lo que hace a rv relevante es que esta filosofía no es nueva ni experimental, es exactamente el modelo que ya adoptaron con éxito gestores de paquetes modernos en otros ecosistemas: uv en Python y Cargo en Rust operan bajo el mismo principio declarativo, con un archivo central de configuración que describe el estado deseado y un lockfile que lo garantiza. rv trae ese estándar a R, que históricamente había quedado rezagado en este aspecto frente a otros lenguajes. El rproject.toml cumple el mismo rol que el pyproject.toml en Python o el Cargo.toml en Rust: es la fuente de verdad del proyecto, versionable, legible y reproducible.
Adoptar rv implica también adoptar un conjunto de buenas prácticas que van más allá de la herramienta en sí: tratar el entorno como código, versionar la configuración junto al proyecto, controlar explícitamente las fuentes de los paquetes, y separar las dependencias de cada proyecto del sistema global. Estas prácticas, ya normalizadas en otros ecosistemas, elevan la reproducibilidad y la colaboración en proyectos de R al mismo nivel de rigor con el que se trata el código fuente.
Referencias
A2-Ai. (n.d.). rv. rv docs. https://a2-ai.github.io/rv-docs/
Wickham, H. (2021). Mastering Shiny. O'Reilly Media. Retrieved June 22, 2026, from https://mastering-shiny.org/