はじめに:なぜ私たちは `uv` へ移行すべきなのか
テックリードである私たちが日々直面する最大のフラストレーションの一つ、それは「依存関係解決と仮想環境構築の待ち時間」ではないでしょうか。
数年前、Pythonのパッケージ管理エコシステムは `Poetry` の登場によって劇的に洗練されました。厳密なロックファイル (`poetry.lock`)、美しくモダナイズされた `pyproject.toml` によるメタデータ管理。私たちの開発体験は確かに底上げされました。しかし、プロジェクトが巨大化し、依存パッケージが数百を超え、マイクロサービス間の共通ライブラリが増加するにつれて、Poetryの「遅さ」がボトルネックとして牙をむき始めました。
- 「`poetry install` の依存関係解決に数分かかる」
- 「CI/CDパイプラインのキャッシュヒット率が低く、ビルド時間が肥大化している」
- 「Dockerイメージのビルドレイヤーでpip/Poetryが足かせになっている」
ここで登場したのが、Astral社がRustで完全再実装した超高速パッケージマネージャー `uv` です。
`uv` は単なる「速いpip」ではありません。Poetryやvirtualenv、pip-tools、pyenvの機能を単一のバイナリで内包しつつ、依存関係の解決速度を Poetryの10倍〜100倍 という圧倒的な次元へと引き上げました。
本記事では、既存のPoetryプロジェクトをノーリスクで `uv` へ完全移行し、チーム全体の開発スピードとCI/CDのパフォーマンスを劇的に向上させるための実践的アプローチを、アーキテクトの視点から余すところなく解説します。
—
1. 内部構造の理解:Poetryとuvは何が違うのか
移行作業に入る前に、両者の「裏側で何が起きているか」を理解しておく必要があります。ここを誤ると、移行後に思わぬ挙動の違い(特に依存関係の厳密性やスクリプト実行パス)でハマることになります。
依存関係解決エンジンとキャッシュ機構
- Poetry: Python(またはpoetry-core)で実装されたリゾルバを持ちます。PyPIへのネットワークリクエストとバージョン制約のバックトラッキングに時間がかかります。
- uv: グローバルなハードリンクキャッシュ(Global Cache)を強烈に活用します。一度ダウンロードしたホイールはシステム全体で共有され、プロジェクト間で重複コピーされることがありません。Rustの並行処理能力を限界まで活かした依存関係解決は、一瞬で完了します。
`pyproject.toml` の互換性
朗報なのは、`uv` は PEP 621(Pythonプロジェクトの標準メタデータ)および PEP 735(依存関係グループ)を完全にサポートしている点です。Poetryが使用する `[tool.poetry]` テーブルはそのまま残しても `uv` は動作しますが、最終的には標準化された `[project]` テーブルへの移行を視野に入れるのがベストプラクティスです。
—
2. ステップ・バイ・ステップ移行ガイド
既存のPoetryプロジェクトを `uv` へ移行する手順を、安全かつ確実に実行するためのステップに分解して解説します。
Step 1: 開発環境への `uv` 導入
まずは開発マシンのシェルに `uv` をインストールします。公式の推奨インストーラーを使用します(Homebrew等でも可能ですが、シェルスクリプトによる導入が最もクリーンです)。
公式インストーラーによるインストール(macOS / Linux)
curl -LsSf https://astral.sh/uv/install.sh | sh
インストール確認
uv –version
出力例: uv 0.5.x (以降のバージョン)
Step 2: 既存 `poetry.lock` から `uv.lock` への変換
Poetryの資産である `poetry.lock` を、`uv` の超高速ロックファイル形式に移行します。`uv` は既存の `poetry.lock` を読み込んで解釈することが可能です。
Poetryのロックファイルをベースに、uvの環境とロックファイルを生成
uv lock
このコマンドを実行すると、プロジェクトルートに `uv.lock` が生成されます。Poetryの `poetry.lock` はこの時点では削除しなくても共存可能ですが、移行完了の判断を下した時点で削除します。
Step 3: 仮想環境の構築と同期
Poetryはプロジェクトローカル(またはグローバル)に `.venv` を作成しますが、`uv` も同様に `.venv` を標準で作成します。
Pythonのバージョンを指定して仮想環境を作成し、依存関係を爆速で同期
uv sync –python 3.11
解説: `uv sync` は、`uv.lock` に記述された正確なバージョンを `.venv` に適用します。Poetryの `poetry install` に相当しますが、体感で10倍以上の速度で完了します。
—
3. 実用的な設定ファイル(pyproject.toml)のベストプラクティス構成例
Poetry依存の記述から、標準(PEP 621)をベースにしつつ `uv` の恩恵を最大限に受ける `pyproject.toml` の構成例を提示します。
[project]
プロジェクトの基本情報(PEP 621準拠)
name = “enterprise-backend-service”
version = “1.0.0”
description = “High-performance enterprise microservice using uv”
readme = “README.md”
requires-python = “>=3.11”
dependencies = [
# 本番環境で必須の依存パッケージ
“fastapi>=0.110.0”,
“uvicorn[standard]>=0.28.0”,
“pydantic>=2.6.0”,
“sqlalchemy>=2.0.25”,
“psycopg[binary]>=3.1.18”,
]
[dependency-groups]
開発・テスト・リント用グループ(PEP 735準拠:Poetryの [tool.poetry.group.dev.dependencies] に相当)
dev = [
“pytest>=8.0.0”,
“pytest-cov>=4.1.0”,
“ruff>=0.2.1”,
“mypy>=1.8.0”,
]
[tool.uv]
uv固有の詳細設定
仮想環境を常にプロジェクトルートの .venv に作成するよう強制
venv = “.venv”
開発用グループも含めてデフォルトで同期する設定
package = true
なぜこの構成が良いのか?
Poetry独自の `[tool.poetry.dependencies]` を排除し、PEP標準の `[project]` テーブルを採用することで、将来的に他のツール(HatchやFlit、Ryeなど)へ乗り換える際のロックインを防ぎます。また、`[dependency-groups]` を用いることで、Poetryの冗長なグループ定義よりスッキリとした構造になります。
—
4. CI/CDパイプラインの高速化:GitHub Actions 設定例
`uv` を導入する最大のメリットの一つが、CI/CD(GitHub Actionsなど)におけるビルド時間の劇的な短縮です。公式が提供するアクション `astral-sh/setup-uv` を用いることで、キャッシュの恩恵を最大化できます。
以下に、テストとリントを実行する実用的なワークフローのベストプラクティスを示します。
name: CI/CD Pipeline
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
validate:
name: Lint and Test with uv
runs-on: ubuntu-latest
steps:
# 1. リポジトリのチェックアウト
- name: Checkout repository
uses: actions/checkout@v4
# 2. Astral公式の uv セットアップアクションを使用
# 自動的に uv のバイナリをダウンロード・配置し、高速なキャッシュ機構を有効化する
- name: Set up uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true
cache-dependency-lock-file: “uv.lock”
# 3. Python環境のセットアップ(uvが自動で指定バージョンのPythonを取得・管理する)
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: “3.11”
# 4. 依存関係の同期(uv sync はキャッシュがあれば数秒で完了する)
- name: Install dependencies
run: |
uv sync –frozen
# 5. リンター(Ruff)の実行
- name: Run Ruff (Linter & Formatter check)
run: |
uv run ruff check .
# 6. 型チェック(Mypy)の実行
- name: Run Mypy
run: |
uv run mypy src/
# 7. テスト(Pytest)の実行
- name: Run Pytest
run: |
uv run pytest –cov=src
アーキテクトのインサイト:`uv sync –frozen` の重要性
CI環境では必ず `–frozen` フラグを付与してください。これにより、`uv.lock` が変更されている場合にエラーを吐き出し、ロックファイルと `pyproject.toml` の不整合によるCIのサイレントバグを完全に防ぎます。また、`uv run` を使うことで、仮想環境の有効化(`source .venv/bin/activate`)を明示的に行うことなく、プロジェクトのコンテキストでコマンドを実行できます。
—
5. プロフェッショナルのための実践テクニック
日々の開発効率を限界まで引き上げるための、知る人ぞ知るテクニックを共有します。
1. エディター(VS Code / PyCharm)連携のポイント
`uv` によって作成された `.venv` は、従来のPoetryが作成するものと構造(Pythonバイナリやサイトパッケージの配置)が完全に同一です。そのため、VS Codeの Python インタープリターとして `./.venv/bin/python` を指定するだけで、既存のワークフローを一切変えずにシームレスに連携できます。
2. スクリプト実行のショートカット:`uv run`
従来のPoetryでは `poetry run pytest` と打つ必要がありましたが、`uv` でも同様に `uv run` が使えます。さらに、`uv` はローカルに存在しない一時的なパッケージをその場で実行する機能(`uvx` / `uv tool run`)も持っています。
プロジェクトの仮想環境を汚さずに、最新の ruff を一時実行してフォーマット
uvx ruff format .
3. Poetryからの完全脱却チェックリスト
移行を完了し、チーム全体でPoetryを完全に廃止する際は、以下のファイルと設定を確認してください。
- `poetry.lock` の削除
- CI/CD設定から `poetry` コマンドの排除
- Dockerfile 内のビルドステージにおける `pip install poetry` の廃止と、`uv` バイナリのマルチステージビルドへの統合
—
おわりに
Poetryから `uv` への移行は、単なる「ツールのおもちゃ変え」ではありません。それは、開発チーム全体のタイムロスを根絶し、インフラコスト(CIのランニングコスト)を削減し、何よりもエンジニアが「待ち時間」という名のストレスから解放されるための、極めてレバレッジの高い投資です。
今日からあなたのプロジェクトでも `uv` を導入し、その圧倒的なスピードを体感してください。あなたのコードベースとチームは、その変化に必ずや感謝するはずです。