- Ao migrar para uv, a velocidade de instalação de dependências Python fica cerca de 10 vezes mais rápida do que com pip, e também é possível executar como usuário não root sem um venv separado
- Com base em pyproject.toml, basta declarar apenas as dependências de nível superior e o uv gerencia automaticamente o arquivo de lock, oferecendo árvore de dependências e controle exato de versões superiores ao
pip freeze
- No Dockerfile, são necessárias mudanças passo a passo, como copiar os binários uv e uvx, usar os arquivos pyproject.toml/uv.lock e configurar variáveis de ambiente
- Com comandos como uv sync/add/remove e uv:outdated, é possível adicionar, remover e atualizar dependências com facilidade, além de verificar as versões mais recentes dos pacotes
- Fica mais fácil manter o arquivo de lock e atualizar dependências regularmente, o que ajuda a garantir consistência em colaboração e ambientes de deploy
Instalação de dependências 10x mais rápida, sem venv e com ambiente não root
- uv é uma ferramenta que melhora bastante a velocidade de instalação de dependências em projetos Python em comparação ao pip tradicional
- Com a adoção do uv, é possível obter cerca de 10 vezes mais velocidade de instalação em comparação ao pip em vários projetos, como Flask e Django
- Mesmo sem um ambiente virtual separado (venv), é possível executar com segurança dentro do contêiner como usuário não root
pyproject.toml vs requirements.txt
- Em vez do tradicional requirements.txt, basta declarar apenas as dependências de nível superior no arquivo pyproject.toml, e o uv gera automaticamente o arquivo uv.lock
- Adicionar o item
[project] dependencies em pyproject.toml
- Remover o
requirements.txt existente
- O arquivo de lock do uv é semelhante ao resultado de
pip freeze, mas inclui árvore de dependências e informações de versão mais precisas
Mudanças na configuração do Dockerfile
- Usar os binários uv e uvx copiando-os para o contêiner (binários Rust compilados estaticamente)
- Em vez dos antigos
requirements*.txt, copiar os arquivos pyproject.toml e uv.lock*
- Adicionar variáveis de ambiente:
UV_COMPILE_BYTECODE=1: pré-compila para bytecode durante a etapa de build
UV_PROJECT_ENVIRONMENT="/home/python/.local": instala os pacotes em um caminho específico sem criar um venv separado
- O comando de instalação de dependências também muda de
pip3-install para uv-install
- Exemplo:
RUN chmod 0755 bin/* && bin/uv-install
Gerenciamento de dependências: adicionar, remover, atualizar e mais
- É possível executar comandos do uv dentro do contêiner com um script
run separado
./run deps:install: instala após construir a imagem e exporta o arquivo de lock para o host
./run deps:install --no-build: atualiza apenas o arquivo de lock sem fazer build
./run uv add mypackage --no-sync: atualiza apenas pyproject.toml e o arquivo de lock; a instalação real é executada separadamente
./run uv remove mypackage --no-sync: remove o pacote
./run uv:outdated: verifica a versão mais recente das dependências atuais
Vídeo e guia prático disponíveis
- Há demonstrações reais e exemplos de
git diff cobrindo adoção do uv, escrita de pyproject.toml, mudanças no Dockerfile, comandos de lock/sync, adição/remoção de dependências e verificação de versões mais recentes
- Também é possível consultar os diffs de migração de dois projetos, Flask e Django
2 comentários
Eu já estava pensando em migrar o que eu implantava com o Poetry, e isso parece estável e simples ^^
Comentários do Hacker News
Vale notar que o uv oferece um fluxo de trabalho que substitui diretamente pyenv, virtualenv e pip. Não é um modelo imposto por lockfile ou
pyproject.toml. Com o comandouv python pin <version>, ele cria um arquivo.python-versionno diretório atual; comuv virtualenv, baixa a versão do Python como o pyenv e cria o ambiente virtual.venv; comuv pip install -r requirements.txt, instala os pacotes derequirements.txt; e comuv run <command>, executa comandos incluindo variáveis de ambiente do arquivo.env. Só é preciso tomar cuidado com a prioridade das variáveis de ambiente (issue relacionada)uv pipfica lento e não sei por quê; talvez seja algo do ambiente de rede da empresapyproject.toml, então fico na dúvida se o arquivo.python-versioné realmente necessárioEsse tipo de abordagem acaba esvaziando o propósito de existir um lock file. Se o arquivo não existe ou está inválido, isso indica um problema sério no lock file e o ideal é que alguém familiarizado com o projeto trate isso manualmente. Caso contrário, não faz sentido manter lock file. No CI, trocar o lock file automaticamente pode gerar confusão
uv lockfalha com uma mensagem amigável, e oerrexitdo shell interrompe tudo imediatamente. O redirecionamento de erro emuv lock --checké para evitar que o mesmo erro apareça duas vezes. Se você corromper o lock file de propósito e rodar o script, o build para com uma mensagem de erro específica. Reescrevi o script comif-elsepara ficar mais claro. Se o lock file não existir, o fluxo correto é criar um novo. Aí é só gerar e fazer commituv sync --locked. Se o lock file não existir ou estiver desatualizado, ele falha de forma explícita. Recomendo sempre fazer o build com a opção--locked--frozen, o lock file não deveria ser atualizado, mas na prática acontece o contrário. Concordo que, se o lock file não existe ou não bate, precisa haver intervenção humanaSou totalmente contra ferramentas de Python serem desenvolvidas em linguagens que não sejam Python. C já existe, e CPython já é padronizado, então não vejo por que precisar de uma nova linguagem como Rust. O pacote Pendulum demorou mais de 7 meses para oferecer suporte ao 3.13, e acredito que isso aconteceu porque, por ser nativo em Rust, faltavam pessoas capazes de corrigir o problema. Se fosse em C, eu mesmo teria consertado. (issue relacionada) Idealmente, se você quer criar um datetime rápido em uma linguagem externa como Rust, o certo seria fazê-lo via FFI de uma forma reutilizável por várias linguagens. Ainda não gosto muito da base em Rust, e até entendo por que a comunidade Linux resiste a isso
É preciso ter cuidado ao usar uv no lugar de pip. Por padrão, ele não gera arquivos
.pyc, então a inicialização do serviço pode ficar mais lenta (referência)Ao usar uv em um contêiner Flask, a diferença no tempo de build não é só grande a ponto de parecer interminável, como o processo de instalação também fica muito mais previsível. Não existe mais aquela frustração de as versões das dependências mudarem com pip. Basta usar
pyproject.tomle rodaruv lock. No Docker, se você copiar apenaspyproject.tomleuv.lock(HOT COPY) e executaruv sync --frozen --no-install-project, a camada de instalação pode ser armazenada em cache sem incluir o código do app. Se você já sofreu por precisar reconstruir a camada inteira quando muda um único pacote, entende por que isso é importante. Usando a variável de ambienteUV_PROJECT_ENVIRONMENT=/home/python/.local, dá para pré-aquecer a imagem base semvenv, compartilhar builds e reduzir custos de infraestrutura. Com a opçãoUV_COMPILE_BYTECODE=1, arquivos.pycsão gerados no build. Isso elimina ambientes mutáveis e força reprodutibilidade; se o build falhar, fica claro que a responsabilidade é do lockfileMesmo em 2025, empacotamento e gerenciamento de dependências em Python continuam sendo uma bagunça
requirements.txtevenvjá é suficienteTenho curiosidade sobre a comparação de segurança entre gerenciadores de pacotes Python como uv, pip e conda. Velocidade é boa, mas considero a segurança do gerenciador muito mais importante
Como alguém que publica pacotes no PyPI, pessoalmente quero usar uv pela velocidade, mas não posso migrar facilmente se não houver garantia de que ele se comporta exatamente como o pip. Se um usuário tiver erro com “pip install xxx”, eu também preciso reproduzir e depurar no mesmo ambiente
Acho que o uv é uma das mudanças mais positivas recentes no empacotamento Python: você simplesmente executa e ele entrega bons resultados
Também foi apresentado um excelente guia para usar uv na construção de contêineres de produção (ver guia)