uv para Python: guía práctica para reemplazar pip, venv y pip-tools en tu equipo
Crear un entorno virtual, instalar dependencias, fijar versiones con pip-tools, manejar versiones de Python con pyenv e instalar herramientas de línea de comandos con pipx: en muchos proyectos Python eso son cinco herramientas distintas. uv, el gestor de paquetes y proyectos de Astral (los creadores de Ruff), propone reemplazarlas con un solo binario escrito en Rust. Su documentación afirma que es entre 10 y 100 veces más rápido que pip.
Lo presentamos en un Short de herramientas; acá va la versión completa, pensada para un equipo que quiere evaluar la migración sin sorpresas.
Qué reemplaza uv
Según la documentación oficial, uv cubre el trabajo de pip, pip-tools, pipx, poetry, pyenv, twine y virtualenv, entre otros. Las piezas principales:
| Necesidad | Antes | Con uv |
|---|---|---|
| Crear entorno virtual | python -m venv .venv |
uv venv (o automático con uv sync) |
| Instalar dependencias | pip install -r requirements.txt |
uv sync o uv pip install -r requirements.txt |
| Fijar versiones | pip-compile |
uv lock / uv pip compile |
| Versiones de Python | pyenv install 3.12 |
uv python install 3.12 |
| Herramientas CLI | pipx install ruff |
uv tool install ruff o uvx ruff |
| Scripts sueltos con dependencias | entorno manual | uv run script.py con metadatos inline |
Además se puede instalar sin tener Rust ni Python previamente, y funciona en macOS, Linux y Windows.
Instalación
El instalador oficial:
# macOS y Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Windows
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
También se puede instalar con pip, Homebrew y otros métodos listados en la página de instalación. En entornos corporativos, conviene fijar una versión concreta en lugar de "la última".
Flujo de proyecto: init, add, run
El flujo básico para un proyecto nuevo:
uv init mi-app # crea pyproject.toml y la estructura mínima
cd mi-app
uv add requests # agrega la dependencia, crea .venv y actualiza uv.lock
uv add --dev pytest # dependencia de desarrollo
uv run python app.py # ejecuta dentro del entorno del proyecto
uv run pytest
Dos archivos importan:
pyproject.toml: las dependencias declaradas, con rangos de versión.uv.lock: el lockfile universal con las versiones exactas resueltas. Se versiona en git.
uv run verifica que el entorno esté sincronizado con el lockfile antes de ejecutar, así que no hace falta "activar" el entorno virtual para el uso diario.
Migrar un proyecto existente sin romper nada
No hace falta migrar todo de golpe. uv tiene una interfaz compatible con pip que sirve como primer paso:
# Paso 1: mismo flujo, más rápido
uv venv
uv pip install -r requirements.txt
# Paso 2: reemplazar pip-tools
uv pip compile requirements.in -o requirements.txt
Cuando el equipo esté cómodo, el paso siguiente es pasar al flujo de proyecto con pyproject.toml y uv.lock. Si alguna herramienta de despliegue todavía necesita un requirements.txt, se puede generar desde el lockfile:
uv export --format requirements.txt -o requirements.txt
uv export también soporta pylock.toml (PEP 751) y CycloneDX 1.5 en JSON, útil si necesitás un SBOM.
Scripts sueltos con dependencias declaradas
Una de las funciones más prácticas para tareas de mantenimiento o automatizaciones chicas: declarar las dependencias dentro del propio script.
echo 'import requests; print(requests.get("https://astral.sh"))' > ejemplo.py
uv add --script ejemplo.py requests # agrega metadatos inline al archivo
uv run ejemplo.py # lo ejecuta en un entorno aislado
El script queda autocontenido: cualquiera con uv puede ejecutarlo sin preparar nada.
uv en CI
En integración continua, la regla es simple: el pipeline tiene que fallar si el lockfile no refleja pyproject.toml. Para eso existe --locked:
uv sync --locked # falla si uv.lock tendría que cambiar
uv run pytest
La documentación también ofrece --frozen, que usa el lockfile tal como está sin verificarlo contra pyproject.toml. Para CI, --locked es la opción más segura porque detecta lockfiles desactualizados. Astral mantiene una integración oficial para GitHub Actions y una guía para otros sistemas de CI.
uv en Docker
La guía oficial de Docker muestra cómo copiar los binarios desde la imagen de uv. Conviene fijar la versión (o incluso el digest) en lugar de usar latest:
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:0.12.20 /uv /uvx /bin/
WORKDIR /app
COPY pyproject.toml uv.lock ./
RUN uv sync --locked --no-install-project
COPY . .
RUN uv sync --locked
CMD ["uv", "run", "python", "app.py"]
Separar la instalación de dependencias de la copia del código aprovecha la caché de capas de Docker: si solo cambia tu código, las dependencias no se reinstalan.
Seguridad de dependencias: exclude-newer
uv tiene una opción que ayuda contra paquetes maliciosos recién publicados: exclude-newer, que limita los candidatos a los archivos subidos antes de una fecha o de una ventana de tiempo. Acepta fechas RFC 3339 o duraciones como 7 days:
# pyproject.toml
[tool.uv]
exclude-newer = "7 days"
Con esto, una versión publicada hace unas horas (por ejemplo, tras el robo de credenciales de un mantenedor) no entra en tu resolución hasta que pasen siete días. Tiene un costo: los parches de seguridad urgentes también esperan, así que conviene combinarlo con --exclude-newer-package para excepciones puntuales.
Qué hacer con esto
Un plan de adopción gradual:
- Probar
uv pip installen local y en CI en un proyecto no crítico, y medir el tiempo antes y después. - Reemplazar pip-tools por
uv pip compiledonde se use. - Migrar un proyecto al flujo
pyproject.toml+uv.locky documentarlo en el README. - Usar
uv sync --lockeden CI. - Fijar la versión de uv en Docker y en CI.
- Evaluar
exclude-newercomo política de dependencias. - Definir una convención de equipo: un solo gestor por repo, sin mezclar pip, poetry y uv.
La velocidad es lo primero que se nota, pero el beneficio más duradero es tener un solo flujo reproducible para todo el equipo.
¿Tu equipo ya migró a uv o sigue con la combinación de pip, venv y pip-tools?
Lecturas relacionadas
- Seguridad de la cadena de suministro en npm y PyPI: controles concretos después de Shai-Hulud: lockfiles, edad mínima de versiones, scripts de instalación y trusted publishing después de Shai-Hulud.
- Cómo escribir ADRs (Architecture Decision Records): plantilla, ejemplos y buenas prácticas: qué decisiones documentar, una plantilla en Markdown y cómo sumar ADRs al flujo de PRs.
En video (Short de menos de 1 minuto): uv: instala dependencias de Python hasta 100× más rápido
Fuentes
- uv, documentación oficial: https://docs.astral.sh/uv/
- uv, instalación: https://docs.astral.sh/uv/getting-started/installation/
- uv, referencia de la CLI: https://docs.astral.sh/uv/reference/cli/
- uv, referencia de settings (
exclude-newer): https://docs.astral.sh/uv/reference/settings/ - uv, guía de integración con Docker: https://docs.astral.sh/uv/guides/integration/docker/
- uv, guía de integración con GitHub Actions: https://docs.astral.sh/uv/guides/integration/github/