---
title: "uv: reseña del gestor de paquetes de Python"
description: Gestionar dependencias en Python puede ser mucho más simple, rápido y reproducible. Descubre cómo uv reúne en una sola herramienta la gestión de paquetes, entornos y versiones de Python, y cómo facilita el trabajo diario con proyectos más ordenados y fáciles de mantener.
---

[ixblog | ixpantia](https://www.ixpantia.com/es/blog)

# [uv: reseña del gestor de paquetes de Python](https://www.ixpantia.com/es/blog/uv-gestor-paquetes-python)

 Escrito por [Nicole Vilca, Michael Suárez y Antonio Chávez](https://www.ixpantia.com/es/blog/author/nicole-vilca-michael-suárez-y-antonio-chávez) | Oct 22, 2026, 11:13:01 PM

 

### **El problema que uv quiere resolver**

Una de las grandes fortalezas de Python es su amplio ecosistema de librerías fácilmente accesibles a través de pip (Python Package Installer), una herramienta incluida por defecto al instalar Python. El comando “`pip install pandas`” es probablemente el primero que se aprende en un curso de Ciencia de Datos. En esencia, este comando instala la versión más reciente y estable de librería en el sistema operativo, y queda disponible globalmente para cualquier otro proyecto.

No obstante, la instalación de librerías a través de pip conlleva el riesgo de encontrar un conflicto de dependencias. Coloquialmente conocido como “Dependency hell”, ocurre cuando dos proyectos necesitan versiones diferentes de una misma dependencia. La solución tradicional implica degradar la versión global de la librería problemática hasta resolver la incompatibilidad. A veces la resolución de la incompatibilidad no es aparente, y el debuggeo puede tomar horas. Adicionalmente, si en otro proyecto necesitamos una versión más reciente, debemos reinstalar y actualizar nuevamente la versión global de la librería.

Este riesgo es mayor al desarrollar aplicaciones complejas en Python con múltiples dependencias. Y para tareas sencillas de Ciencia de Datos, que por lo general suelen depender de pandas, requests y alguna librería de visualización, el riesgo de reproducibilidad es menor, pero no inexistente. Por ejemplo, puede que, en el futuro, con el lanzamiento de pandas 4.0, se cambie el comportamiento por defecto de alguna función (como el [copy-on-write](https://pandas.pydata.org/docs/user_guide/copy_on_write.html)), y un script viejo que asumía el comportamiento anterior deje de funcionar.

Existen y existieron muchas aproximaciones para la gestión de dependencias. Por ejemplo, Python 3.3, lanzado en 2012, introdujo el módulo *venv* (PEP 405), que incorporó el soporte para la creación de entornos virtuales aislados y con dependencias propias, eliminando la necesidad de instalar una herramienta de terceros como *virtualenv.* Paralelamente, la comunidad científica adoptó Anaconda, un gestor de paquetes y entornos capaz de instalar no solo librerías de Python sino también dependencias binarias. Resolvía el problema de aislamiento y compilación, pero a costa de entornos pesados y resoluciones lentas. En 2018, surgió Poetry como un paso importante para la gestión de dependencias, manejo de entornos virtuales y empaquetado, todo alrededor de una sola herramienta y de un pyproject.toml, pero seguía dejando fuera la gestión de versiones de Python, introducía un formato propio dentro del *toml*, y la resolución de dependencias podía ser lenta.

**Es así como en 2024 surgió uv: una sola herramienta que reemplaza a pip, venv, pyenv, requirements.txt y gran parte de Poetry, con tiempos de instalación y buenas prácticas que cambian la experiencia diaria en la gestión de dependencias.**

### **¿Por qué está escrito en Rust y qué significa eso para quien desarrolla en Python?**

Y es preciso señalar que uv está escrito en Rust, a diferencia de pip y poetry, lo que les pone un techo a su velocidad. Python es un lenguaje interpretado, cómodo para escribir pero lento para tareas como resolver cientos de dependencias, descargar paquetes en paralelo o copiar archivos al entorno virtual. Rust, en cambio, se compila directamente a código de máquina y maneja muy bien la concurrencia. Por eso uv instala en segundos lo que con pip puede tardar minutos. Para quien desarrolla en Python, no hace falta saber Rust ni instalarlo: uv se usa desde la terminal como cualquier otro comando. Lo único que se nota es la velocidad, sobre todo al crear entornos desde cero o cuando el proyecto tiene muchas dependencias.

uv tampoco es un caso aislado. En los últimos años varias herramientas del ecosistema se han reescrito o construido en Rust: Polars como alternativa a pandas, Ruff como linter y formateador (del mismo equipo que creó uv, Astral), o el núcleo de pydantic. La idea se repite: mantener Python como el lenguaje con el que trabajamos y dejar que Rust haga el trabajo pesado por detrás.

### **El flujo tradicional con pip + venv + requirements.txt**

Antes de ver cómo se hace con uv, conviene repasar el flujo que la mayoría aprendimos con pip. Son tres piezas claves que vienen con Python: `venv` para aislar en entorno, `pip` para instalar y `requirements.txt` para registrar lo instalado.

 Ejemplo de flujo tradicional 

`# 1. Crear el entorno virtual python -m venv .venv # 2. Activarlo source .venv/bin/activate # 3. Instalar las dependencias pip install pandas requests # 4. Guardar lo instalado en un archivo pip freeze > requirements.txt`

Los puntos débiles de este flujo:

- Son pasos manuales que provienen de diferentes programas; aunque se aprenden con la frecuencia de ejecución, al inicio son fáciles de olvidar.
- El entorno virtual se debe activar cada vez que abrimos una terminal nueva.
- El `requirements.txt` que se genera no distingue las dependencias del proyecto de las dependencias de nuestro entorno global (aunque hay opciones para adaptarlo).
- El comando para activar un entorno virtual es diferente si el usuario usa Windows: `source .venv/bin/activate` ⇒ `.venv\Scripts\Activate.ps1`

### **Introducción al flujo de trabajo de uv**

Veamos cómo uv simplifica este flujo, y la mejor manera de entenderlo es ejecutando. El primer comando es `uv.init`**.**

`uv init`

Con este primer comando, uv crea la carpeta del proyecto con la estructura básica (un *src layout*), un [README.md](http://readme.md) y un archivo `pyproject.toml`*,* el cual es la configuración central del proyecto en Python. Este archivo reúne en un solo lugar centralizado desde los metadatos hasta sus dependencias. Lo desarrollaremos a profundidad más adelante.

El siguiente comando es `uv add <dependencia>`Con este comando se instala la dependencia necesaria y se registra en la lista de dependencias del proyecto en el `pyproject.toml`.

`uv add pandas # instala el paquete pandas y lo registra como una dependencia`

 Un ejemplo de cómo quedaría nuestro `pyproject.toml`**:** el archivo de configuración. 

`[project] name = "example" version = "0.1.0" description = "Add your description here" readme = "README.md" authors = [ { name = "Autor", email = "autor@ixpantia.com" } ] requires-python = ">=3.13" dependencies = [ "pandas>=3.0.6", ] [project.scripts] example = "example:main" [build-system] requires = ["uv_build>=0.12.9,<0.13.0"] build-backend = "uv_build"`

En versiones recientes de uv, se añade la línea `uv build`: Este es el backend para instalar nuestro código como librería de manera local, lo que permite importarla para scripts que utilizan este entorno virtual.

Por último, con `uv sync`, se sincroniza el entorno virtual (.venv) del proyecto para que coincida exactamente con lo especificado en el archivo de bloqueo (uv.lock).

`uv sync`

De manera resumida, eso es todo el flujo de uv. Observa lo que ya no es necesario hacer: no creamos un entorno virtual ni lo activamos, tampoco es necesario editar archivos a mano. uv crea una carpeta *.venv* dentro del proyecto la primera vez que hace falta. La librería queda instalada solo en ese proyecto, no en el sistema operativo, así que otro proyecto puede usar otras versiones sin conflictos. Esto ataca de raíz el problema del conflicto de dependencias que hablamos en el prefacio.

### **Una vista detallada de los archivos generados por uv**

En esta sección, entraremos en detalle sobre los archivos clave generador por uv después de ejecutar los comandos mencionados:

- `pyproject.toml`: es el archivo de configuración del proyecto. Describe qué es (nombre, versión, versión mínima de Python) y qué necesita, es decir, las dependencias que nosotros elegimos. Ya no hace falta repartir la configuración en múltiples archivos dispersos, como *setup.py, requirements.text* o *setup.cfg*.
- `uv.lock`: generado por uv automáticamente y registra el resultado de resolver esas dependencias manejando versiones compatibles y curadas.

Una analogía para entenderlos de manera simple: si el `pyproject.toml` es la lista de lo que queremos (una receta estructurada de lo que se requiere, en qué versión y de dónde tomarlo), el `uv.lock` es el registro de lo que realmente se instaló.

En el `pyproject.toml` escribimos requisitos flexibles, como "`pandas>=3.0.6`”, “*cualquier versión desde la 3.0.6 en adelante*”. Esa flexibilidad es cómoda, pero tiene un costo: dos personas que instalen el proyecto en momentos distintos pueden terminar con versiones distintas. Es el mismo riesgo de reproducibilidad que mencionamos con pandas 4.0: el código no cambió, pero lo que se instala sí.

El `uv.lock` resuelve esto. Cuando agregamos o modificamos una dependencia, uv calcula qué versiones concretas se instalaron finalmente para que todo sea compatible entre sí. Eso incluye no solo los paquetes que pedimos, sino también los que se necesitan por debajo (las dependencias transitivas). El resultado queda guardado en el archivo: cada paquete con su versión exacta, de dónde se descargó y su hash para verificar que el archivo es el esperado.

Algunas ideas clave sobre cómo funciona el `uv.lock`:

- **Es universal.** Como mencionamos arriba, el archivo no depende del sistema operativo. Los usuarios de Window, como los de Linux terminan instalando exactamente las mismas versiones.
- **Lo administra uv, no nosotros.** Es un archivo de texto, pero no está pensado para editarse a mano (algo que sí es posible para el caso del *pyproject.toml*). uv lo actualiza cada vez que corremos:
- `uv add <dependencia>,`
- `uv remove <dependencia>,o`
- `uv sync`
- **Se debe versionar en Git junto con nuestro código**. Así, quien clone el proyecto reproduce el entorno con un solo comando, `uv sync`, y obtiene las mismas versiones que usó el autor.
- **Actualizar es una decisión explícita.** Mientras el archivo exista, uv respeta las versiones guardadas. Si queremos subir de versión, lo pedimos (por ejemplo, con `uv lock --upgrade`). Así, el día que salga pandas 4.0, nuestro script viejo seguirá corriendo con la versión con la que lo escribimos, hasta que decidamos migrar.

En resumen, el `pyproject.toml` expresa nuestra intención y el `uv.lock` garantiza el resultado. Entre los dos, “*en mi máquina funciona*” deja de ser un problema.

##### Ejemplo del archivo de bloqueo uv.lock

`version = 1 revision = 3 requires-python = ">=3.13" resolution-markers = [...] [[package]] name = "example" version = "0.1.0" source = { editable = "." } dependencies = [ { name = "pandas" }, ] [package.metadata] requires-dist = [ { name = "pandas", specifier = ">=3.0.6" }, ] [[package]] name = "pandas" version = "3.0.6" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "numpy" }, { name = "python-dateutil" }, { name = "tzdata", marker = "sys_platform == 'emscripten' or sys_platform == 'win32'" }, ] sdist = {...} wheels = [...]`

### **¿Qué más hace uv?**

Con `uv init`, uv add y `uv sync` ya tenemos un proyecto funcional. Pero uv también reemplaza varias herramientas que antes teníamos que instalar y aprender por separado.

**Ejecutar código sin activar el entorno: uv run**

Es probablemente el comando que más vamos a usar después de los tres anteriores. uv run ejecuta cualquier script o comando dentro del entorno virtual del proyecto, sin necesidad de activarlo. Antes de correr, revisa que el `.venv```y el `uv.lock` estén al día con el `pyproject.toml` y, si hace falta, los actualiza.

`uv run main.py # corre un script del proyecto uv run pytest # corre las pruebas, si pytest está entre las dependencias`

Si queremos probar algo puntual sin agregarlo al proyecto, podemos usar `--with`. La dependencia se instala solo para esa ejecución y no toca el `pyproject.toml`:

`uv run --with rich main.py`

**Grupos de dependencias y dependencias opcionales**

No todas las librerías que usamos son necesarias para que el proyecto funcione. pytest o ruff nos sirven mientras desarrollamos, pero quien instale nuestra librería no los necesita. Para eso existen los grupos de desarrollo:

`uv add --dev pytest ruff`

uv las registra en una sección aparte del `pyproject.toml` (`[dependency-groups]`), separadas de las dependencias principales.

Las dependencias opcionales (o *extras*) cumplen otro rol: son funcionalidades que el usuario de la librería puede elegir instalar. Por ejemplo, si nuestro paquete puede generar gráficos pero no todos lo van a usar:

bash

`uv add --group graficos matplotlib uv sync --extra graficos`

**Versiones de Python**

uv también gestiona las versiones de Python, algo que antes requería herramientas como pyenv. Si el proyecto pide una versión que no tenemos, uv la descarga sola. También podemos fijarla para el proyecto:

`uv python install 3.12 uv python pin 3.12 # crea un archivo .python-version`

**Versión del proyecto: uv version**

`uv version` muestra la versión de nuestro propio proyecto o librería, y permite subirla (*bump)* sin editar el archivo a mano:

`uv version --bump patch # 0.1.0 → 0.1.1 uv version --bump minor # 0.1.0 → 0.2.0 uv version --bump major # 0.1.0 → 1.0.0`

**Herramientas de línea de comandos: uvx**

Hay herramientas que usamos en muchos proyectos pero que no forman parte de ninguno, como ruff. Con uvx las podemos ejecutar en un entorno temporal, sin instalarlas. Si las usamos seguido, podemos instalarlas de forma global para que sean manejadas por uv con `uv tool install`:

`uvx ruff check . uv tool install ruff`

Todo esto, que antes repartíamos entre pip, venv, pyenv, pipx y Poetry, queda en una sola herramienta con la misma lógica.

**¿Cuándo tiene sentido usar uv?**

La respuesta corta es: casi siempre. En **ixpantia** lo usamos en todos nuestros proyectos de Python, desde una librería interna con decenas de dependencias hasta un análisis que solo necesita pandas. Es parte de nuestras buenas prácticas, y lo elegimos por cuatro razones:

- **Es simple.** Con tres comandos tenemos un proyecto listo, y quien llega nuevo al equipo no necesita aprender a combinar cuatro herramientas distintas.
- **La configuración vive en un solo lugar.** El `pyproject.toml` reúne los metadatos, las dependencias y la versión de Python. Basta abrir un archivo para entender qué necesita el proyecto.
- **Es reproducible.** Gracias al `uv.lock`, cualquier persona del equipo, en cualquier sistema operativo, instala exactamente las mismas versiones. Lo mismo pasa cuando el proyecto llega a producción.
- **Es rápido.** Crear un entorno desde cero toma segundos. Eso se nota en el día a día y también en los pipelines de integración continua, donde los entornos se crean una y otra vez.

Incluso en proyectos pequeños, el costo de usar uv es prácticamente cero, y nos ahorra el problema de descubrir meses después que un script ya no corre.

### **Conclusiones**

Volvamos al problema con el que empezamos. Instalar librerías de forma global con pip funciona bien hasta que dos proyectos necesitan versiones distintas de lo mismo, o hasta que una actualización cambia algo que nuestro código daba por hecho. Durante años, la comunidad fue resolviendo partes de ese problema con herramientas distintas: venv para aislar entornos, Anaconda para dependencias binarias, Poetry para centralizar la configuración. Cada una aportó algo, pero ninguna lo resolvía todo.

uv junta esas piezas en una sola herramienta. Cada proyecto tiene su propio entorno, el `pyproject.toml` dice qué necesitamos y el `uv.lock` asegura que todos instalemos exactamente lo mismo, hoy o dentro de un año. Además, al estar escrito en Rust, lo hace lo bastante rápido como para que crear o recrear un entorno deje de ser un trámite que preferimos evitar.

Lo que más valoramos es que no exige cambiar la forma de trabajar. Con `uv init`, `uv add` y `uv sync` ya tenemos un proyecto ordenado y reproducible, y el resto de funciones (uv run, los grupos de dependencias, la gestión de versiones de Python, `uvx`) aparecen cuando las necesitamos. Por eso en ixpantia lo usamos como estándar en todos nuestros proyectos de Python. Si todavía trabajas con pip y `requirements.txt`, te recomendamos probarlo en tu próximo proyecto: la curva de aprendizaje es corta y el día que salga pandas 4.0 lo vas a agradecer.

### Referencias

https://docs.astral.sh/uv/

https://medium.com/@ckmzyol/from-python-3-0-to-3-15-what-really-changed-in-18-years-c5452027e114

[Ver post completo](https://www.ixpantia.com/es/blog/uv-gestor-paquetes-python)

```json
{
  "@context" : "http://schema.org",
  "@type" : "BlogPosting",
  "author" : {
    "@type" : "Person",
    "name" : "Nicole Vilca, Michael Suárez y Antonio Chávez"
  },
  "dateModified" : "2026-10-22T23:13:01.258Z",
  "datePublished" : "2026-10-22T23:13:01Z",
  "headline" : "uv: reseña del gestor de paquetes de Python",
  "image" : {
    "@type" : "ImageObject",
    "height" : 628,
    "url" : "https://40151821.fs1.hubspotusercontent-na1.net/hubfs/40151821/2-Oct-21-2026-04-46-03-1552-PM.png",
    "width" : 1200
  },
  "mainEntityOfPage" : "https://www.ixpantia.com/es/blog/uv-gestor-paquetes-python",
  "publisher" : {
    "@type" : "Organization",
    "logo" : {
      "@type" : "ImageObject",
      "height" : 60,
      "url" : "/hs/hsstatic/content_shared_assets/static-1.4092/img/default-amp-logo.png",
      "width" : 60
    },
    "name" : "ixblog | ixpantia"
  }
}
```