파이썬 프로젝트 하나를 새로 시작할 때 보통 이런 순서를 거칩니다. pyenv로 파이썬 버전을 맞추고, python -m venv .venv로 가상환경을 만들고, pip install로 패키지를 깔고, 의존성 버전을 고정하려면 pip freeze나 poetry를 따로 도입합니다. 도구 네 개가 각자 한 조각씩만 맡고 있어서, 신입 개발자에게 환경 설정을 설명하려면 이 네 가지를 순서대로 다 알려줘야 합니다. uv는 Astral(Ruff를 만든 팀)이 Rust로 작성한 패키지·프로젝트 매니저로, 이 네 도구가 나눠 맡던 역할을 하나의 바이너리로 합쳤습니다.
핵심 개념
- 프로젝트 모드:
uv init으로 프로젝트를 만들면pyproject.toml에 의존성이 정리되고, 가상환경은uv가 알아서.venv에 만들어둡니다.pip처럼 가상환경을 켜고 끄는 걸 신경 쓸 필요가 거의 없습니다. - uv.lock:
poetry.lock과 비슷하지만 플랫폼(OS·아키텍처·파이썬 버전)별 분기까지 하나의 파일에 다 담는 범용 락파일입니다. CI에서 리눅스로 빌드하고 로컬은 macOS를 쓰는 경우에도 락파일이 하나로 공유됩니다. - uv run: 가상환경을 직접 활성화하지 않고도
uv run python script.py처럼 바로 실행할 수 있습니다. 실행 전에pyproject.toml과uv.lock이 어긋나 있으면 먼저 동기화부터 하고 실행합니다. - 파이썬 버전 관리 내장:
pyenv없이도uv python install 3.12로 원하는 파이썬 버전을 받아서 프로젝트별로 고정할 수 있습니다. - uvx:
pipx run과 같은 역할로, 전역 설치 없이 CLI 도구를 그때그때 받아서 실행합니다(uvx ruff check .).
실전 예시
새 프로젝트를 만들면 pyproject.toml과 .venv, uv.lock이 한 번에 갖춰집니다.
uv init my-api
cd my-api
# pyproject.toml
[project]
name = "my-api"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = []
의존성을 추가하면 설치와 동시에 pyproject.toml·uv.lock이 같이 갱신됩니다.
uv add fastapi "uvicorn[standard]"
# pyproject.toml (갱신됨)
dependencies = [
"fastapi>=0.115.0",
"uvicorn[standard]>=0.32.0",
]
테스트나 린트처럼 배포에는 필요 없는 의존성은 그룹으로 분리합니다.
uv add --dev pytest ruff
가상환경을 직접 켜지 않고 바로 실행합니다.
uv run uvicorn main:app --reload
다른 머신에서 그대로 복원할 때는 락파일 기준으로만 설치합니다. 이 명령은 pyproject.toml을 다시 읽지 않고 uv.lock에 적힌 버전 그대로만 설치하므로, CI에서 "로컬에서는 되는데 CI에서는 버전이 다르게 깔린다" 문제를 막아줍니다.
uv sync --frozen
파이썬 버전 자체도 프로젝트에 고정할 수 있습니다.
uv python pin 3.12
이 명령은 프로젝트 루트에 .python-version 파일을 만들고, 이후 uv run·uv sync는 이 버전의 인터프리터를 자동으로 받아서 씁니다. 팀원 컴퓨터에 해당 버전이 없어도 uv가 알아서 내려받기 때문에 "내 파이썬 버전은 3.11인데요"로 시작하는 대화가 줄어듭니다.
비슷한 도구와 비교
| 항목 | uv | pip + venv | Poetry | Conda |
|---|---|---|---|---|
| 설치 속도 | 빠름(Rust, 병렬 다운로드+캐시) | 기준 | uv보다 느림 | 가장 느린 편 |
| 파이썬 버전 관리 | 내장(uv python install) |
없음(pyenv 별도 필요) | 없음(pyenv 별도 필요) | 내장 |
| 락파일 | uv.lock(플랫폼 통합) |
없음(freeze로 흉내) | poetry.lock |
environment.yml + 별도 락 도구 |
표준 pyproject.toml 호환 |
호환 | 해당 없음 | 자체 섹션 의존 큼 | 해당 없음 |
CLI 일회성 실행(pipx 대체) |
uvx 내장 |
없음 | 없음 | 없음 |
Poetry는 오랫동안 사실상 표준이었고 플러그인 생태계도 넓어서, 이미 Poetry로 굳어진 팀이 당장 바꿀 이유는 크지 않습니다. 다만 새 프로젝트라면 설치 속도와 파이썬 버전 관리까지 한 바이너리로 끝난다는 점에서 uv 쪽이 설정할 도구 가짓수가 적습니다. Conda는 비-파이썬 바이너리 의존성(예: CUDA, 시스템 라이브러리)까지 다뤄야 하는 데이터 과학·ML 환경에서는 여전히 대체하기 어렵습니다.
넘어갈 때 걸리는 부분
기존 requirements.txt 기반 프로젝트에 붙일 때는 uv pip install -r requirements.txt처럼 pip 호환 명령으로 먼저 써볼 수 있습니다. 다만 이 모드에서는 uv.lock이 생기지 않으므로, 락파일의 이점을 보려면 결국 uv add로 의존성을 다시 선언하는 프로젝트 모드로 넘어가야 합니다. 사내 PyPI 미러처럼 커스텀 인덱스를 쓰는 환경에서는 pip.conf가 아니라 pyproject.toml의 [[tool.uv.index]]에 따로 설정을 옮겨야 하는 것도 처음 도입할 때 자주 놓치는 부분입니다.
버전은 아직 1.0 이전(0.x) 대역이라 마이너 버전 올릴 때 CLI 플래그가 바뀌는 경우가 종종 있어서, CI에서는 uv 버전을 고정해두는 편이 안전합니다.