uv で Python プロジェクトを依存ロック付きで再現可能にする

uv は Astral(Ruff の開発元)が作る Rust 製の Python パッケージ/プロジェクト管理ツールだ。pip + venv + pip-tools + pyenv あたりの役割を 1 バイナリにまとめ、依存解決が速いこと、そして uv.lock によるクロスプラットフォームな再現可能インストールが扱いやすいことで広く使われるようになった。

この記事では、プロジェクトを作って依存を追加し、uv.lock で別環境でも同じ状態を再現するところまでを、実際のコマンドと出力で確認する。本記事のコマンドは uv 0.4 以降で共通なので、まず uv --version で入っていることを確かめてほしい。

インストールと確認

未導入なら公式のインストーラを使う(macOS / Linux)。

1
curl -LsSf https://astral.sh/uv/install.sh | sh

導入済みかどうかはバージョン表示で確認する。

1
2
uv --version
# 例: uv 0.8.0

uv 本体は単一バイナリで、Python 自体が入っていなくても uv が必要な Python を用意できる(後述)。

プロジェクトを初期化する

uv init で新しいプロジェクトを作る。pyproject.toml.python-version、サンプルスクリプトが生成される。

1
2
3
uv init try-uv && cd try-uv
ls
# pyproject.toml README.md main.py .python-version

生成された pyproject.toml にはプロジェクト名と対応 Python バージョン、依存配列(最初は空)が入っている。

依存を追加すると uv.lock が生まれる

uv add で依存を追加する。ここで仮想環境 .venv の作成、依存解決、pyproject.toml への追記、そして uv.lock の生成までが一度に行われる。

1
uv add requests

追加後、ロックファイルが出来ていることを確認する。

1
2
3
ls uv.lock && grep -m1 'name = "requests"' uv.lock
# uv.lock
# name = "requests"

uv.lock には依存の完全な解決結果(バージョンとハッシュ、プラットフォーム条件)が記録される。これがコミット対象で、再現性の核になる。.venv はコミットしない。

スクリプトを動かす

追加した依存を使うスクリプトを用意する。main.py を次の内容で上書きする。

1
2
3
4
5
import requests

resp = requests.get("https://httpbin.org/get", timeout=10)
print("status:", resp.status_code)
print("url:", resp.json()["url"])

uv run は「ロックと同期してから、その環境でコマンドを実行する」ため、事前の activate は要らない。

1
2
3
uv run main.py
# status: 200
# url: https://httpbin.org/get

uv run は実行のたびに uv.lock.venv の同期を確認するので、「ロックを更新したのに入れ忘れて古い依存で動く」という事故が起きにくい。

別環境で同じ状態を再現する

ここが本題だ。uv.lockpyproject.toml をコミットしておけば、別マシンや CI では uv sync だけでまったく同じ依存構成を作れる。ロックを一切変更させたくない場合は --frozen を付ける。

1
2
# CI や別マシンでの再現(ロックを更新しない)
uv sync --frozen

ロック自体を明示的に作り直したいときは uv lock を単体で実行する。依存の更新は uv lock --upgrade(あるいは特定パッケージだけ uv lock --upgrade-package requests)で行い、差分は uv.lock にだけ現れる。

1
uv lock --upgrade-package requests

「アプリのコードは変えず依存だけ上げた」がロックファイルの diff として明確に残るので、レビューしやすい。

Python 本体も uv が用意する

対応する Python が無ければ uv が取得・固定できる。プロジェクトの Python を 3.12 に固定する例。

1
2
3
4
uv python install 3.12
uv python pin 3.12
cat .python-version
# 3.12

これで .python-version が更新され、以降の uv run / uv sync はその Python を使う。pyenv を別途入れなくても、プロジェクトごとの Python バージョン固定ができる。

使い捨てのツール実行: uvx

Lint やフォーマッタのような「プロジェクトの依存にはしたくないが手元で動かしたいツール」は uvxuv tool run の短縮形)で一時環境から実行できる。インストールせずに ruff を走らせる例。

1
uvx ruff check .

uvx <tool> はツールを隔離した一時環境で実行するので、プロジェクトの pyproject.tomluv.lock を汚さない。

まとめ

uv は「初期化(uv init)→依存追加(uv add)→実行(uv run)→別環境で再現(uv sync --frozen)」という流れを、uv.lock を軸に一貫して扱えるのが強みだ。コミットするのは pyproject.tomluv.lock、実行時は activate 不要、Python 本体も uv が用意できる。手元に uv があれば、上の try-uv の手順をそのままなぞって uv run main.py まで試してほしい。依存を上げたときに uv.lock だけが変わる感覚がつかめるはずだ。

出典


uv で Python プロジェクトを依存ロック付きで再現可能にする
https://blog.hashito.biz/2026/07/11/try-uv-python-reproducible-project/
著者
hashito
作成日
2026年7月11日
著作権