ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • uv.lock과 requirements.txt 차이: 설치 재현은 어떤 파일로 관리할까
    Programming 2026. 9. 13. 21:27
    728x90
    반응형

    뚜껑을 연 칸막이 금속 보관함에 정리된 케이블과 작은 기기들

    뚜껑을 연 칸막이 금속 보관함에 정리된 케이블과 작은 기기들. 이해를 돕기 위한 AI 생성 개념 이미지입니다.

    같은 저장소를 내려받았는데 한 사람에게는 설치되고 다른 사람에게는 깨지는 경우가 있습니다. 이때 “버전을 고정했으니 재현된다”는 말은 절반만 맞습니다. 프로젝트가 허용하는 버전 범위, 실제로 선택한 버전, 그 버전으로 만든 실행 환경을 서로 다른 층으로 봐야 합니다.

    uv 프로젝트라면 보통 pyproject.toml과 uv.lock을 함께 버전 관리하고, CI에서는 잠금 파일을 고치지 않는 검사와 동기화를 실행하는 것이 출발점입니다. requirements.txt도 정확한 버전과 해시를 담을 수 있으므로 파일 이름만 보고 우열을 가를 일은 아닙니다.

    세 파일은 같은 정보를 담지 않습니다

    uv 프로젝트 구조 문서가 설명하는 기본 역할은 다음과 같습니다.

    구성담는 것질문
    pyproject.toml직접 의존성과 허용 범위, 프로젝트 메타데이터이 프로젝트가 무엇을 요구하는가
    uv.lockresolver가 선택한 직접·간접 의존성 정보그 요구에서 무엇을 선택했는가
    .venv현재 장비에 실제 설치된 환경지금 무엇을 실행하고 있는가

    예를 들어 pyproject.toml에 httpx>=0.27,<1이라고 적으면 허용 범위이지 한 버전의 선택이 아닙니다. 잠금 과정에서 httpx와 그 하위 의존성의 구체적인 조합이 uv.lock에 기록됩니다. .venv는 이 정보를 현재 Python과 플랫폼에 맞춰 설치한 결과입니다.

    uv 공식 문서에서 uv.lock은 운영체제·아키텍처·Python 버전 marker를 포함하는 universal/cross-platform lockfile로 설명됩니다. 따라서 같은 uv.lock을 사용해도 Linux와 macOS가 동일한 wheel 파일을 받는다는 뜻은 아닙니다. 중요한 것은 파일 바이트가 모든 장비에서 같다는 약속이 아니라, 프로젝트가 선언한 플랫폼 조건 안에서 resolver의 선택을 기록하고 검증할 수 있다는 점입니다. uv.lock 형식은 uv 전용이므로 다른 도구가 그대로 읽는 범용 파일이라는 뜻도 아닙니다.

    requirements.txt는 낡은 파일이라는 뜻이 아닙니다

    requirements.txt는 형식과 생성 방법에 따라 역할이 달라집니다.

    • requests>=2처럼 범위만 적으면 요구사항 목록에 가깝습니다.
    • 전이 의존성까지 정확한 버전으로 내보내면 잠금 결과의 배포용 표현으로 쓸 수 있습니다.
    • 해시까지 요구하면 내려받는 배포 파일 검증도 강화할 수 있습니다.

    반대로 uv.lock이 있다고 해서 설치가 저절로 안전하거나 애플리케이션이 정상 동작하는 것은 아닙니다. 잠금은 선택된 의존성을 재현하는 장치이지 취약점 검사, 테스트, Python·OS 지원 확인을 대신하지 않습니다.

    둘 중 하나만 고르는 대신 경계를 정하면 됩니다. uv로 개발하는 애플리케이션은 pyproject.toml과 uv.lock을 정본으로 두고, requirements.txt가 필요한 외부 배포 대상에는 잠금 결과를 내보내는 식입니다.

    # 프로젝트 uv.lock에서 requirements.txt를 내보내는 예
    uv export --format requirements.txt
    
    # requirements.in을 별도 입력으로 쓰는 pip 인터페이스 예
    uv pip compile requirements.in -o requirements.txt

    첫 명령은 프로젝트 lock을 다른 형식으로 내보내는 흐름이고, 둘째는 requirements.in을 해석해 별도 requirements.txt를 만드는 흐름입니다. 두 파일이 따로 정본이 되면 갱신 시점이 어긋날 수 있으므로, 생성 명령과 원본 lock 또는 입력 파일의 커밋을 함께 남겨야 합니다. 최신 uv 문서에는 도구 중립적인 PEP 751 pylock.toml도 export·sync 대상으로 소개되므로, 배포 도구가 어떤 형식을 읽는지 먼저 확인하세요.

    lock과 sync는 다른 작업입니다

    uv 잠금·동기화 문서에서 lock은 요구사항을 해결해 uv.lock을 만들거나 갱신하는 일이고, sync는 잠금 결과를 프로젝트 환경에 반영하는 일입니다.

    개발자가 의존성을 바꾼 뒤 평소처럼 실행하면 uv가 필요한 갱신과 동기화를 자동 수행할 수 있습니다. 편하지만 CI에서 이 동작을 그대로 허용하면, 커밋하지 않은 잠금 변경을 빌드 시점에 조용히 만들 수 있습니다. 검증 단계와 갱신 단계를 나누는 이유입니다.

    # pyproject.toml과 uv.lock이 일치하는지만 검사
    uv lock --check
    
    # lock이 최신인지 확인하고, 낡았으면 실패
    uv sync --locked
    
    # lock 최신성 확인 없이 기록된 lock을 그대로 사용
    uv run --frozen ...

    위 명령은 문서에 근거한 사용 예시이며 이 글에서 실행 결과를 측정하지 않았습니다. --locked는 잠금 파일 갱신이 필요하면 실패하도록 하고, --frozen은 최신성 확인 없이 lock을 사용합니다. CI에서 어느 검사를 원하는지 구분해야 합니다. 배포 파이프라인에서 자동 갱신을 허용할지, 개발자가 의존성 변경과 lock diff를 함께 검토하도록 되돌릴지도 팀 규칙으로 정합니다.

    exact sync에서 사라지는 패키지를 확인합니다

    프로젝트 환경에 예전에 수동 설치한 패키지가 남아 있으면 “내 컴퓨터에서만 되는” 상황이 생깁니다. uv의 uv sync는 기본적으로 프로젝트에 필요하지 않은 패키지를 제거하는 exact sync를 사용하지만, uv run은 기본적으로 여분 패키지를 보존하는 inexact sync를 사용합니다. uv run --exact처럼 명시할 수 있으므로 명령별 차이를 기록하세요. 별도로 설치해 둔 도구까지 같은 .venv에 섞었다면 exact sync에서 제거되는 것이 예상치 못한 부작용처럼 보일 수 있습니다.

    그래서 프로젝트 런타임과 개인 CLI 도구를 같은 환경에 섞지 않는 편이 좋습니다. 환경을 정리하기 전에 다음을 기록합니다.

    1. 프로젝트가 선언한 직접 의존성
    2. uv.lock 변경 diff
    3. CI가 사용하는 Python 버전과 플랫폼
    4. 동기화 후 실행할 import·단위·통합 테스트
    5. requirements.txt를 내보냈다면 생성 명령과 원본 커밋

    팀에서 의존성을 올리는 실제 순서

    가령 웹 클라이언트 라이브러리를 올려야 한다고 합시다.

    1. pyproject.toml의 허용 범위를 의도적으로 수정합니다.
    2. uv lock을 실행해 직접·전이 의존성 변경을 확인합니다.
    3. uv.lock의 큰 diff가 예상한 패키지 때문인지 검토합니다.
    4. 깨끗한 환경에서 uv sync --locked로 설치합니다.
    5. 애플리케이션 테스트와 지원 플랫폼 테스트를 실행합니다.
    6. 두 파일을 같은 변경으로 커밋합니다.

    “lock 파일이 바뀌었으니 그냥 포함”하면 예상하지 않은 전이 의존성 변경을 놓칠 수 있습니다. 반대로 pyproject.toml만 커밋하면 동료가 어떤 조합을 설치해야 하는지 결정하는 일을 다시 resolver에 넘기게 됩니다.

    재현 실패를 찾는 체크리스트

    잠금 파일이 같은데 결과가 다르면 다음 순서로 좁힙니다.

    • 두 장비의 Python 구현과 버전이 같은가
    • OS·CPU에 따라 다른 배포 파일이 선택됐는가
    • 환경 변수나 선택적 dependency group이 다른가
    • CI가 lock을 읽는 대신 갱신하지 않았는가
    • 기존 .venv에 선언하지 않은 패키지가 남았는가
    • 패키지 외부의 시스템 라이브러리와 서비스 버전이 다른가

    마지막 항목은 uv.lock 밖의 문제입니다. 데이터베이스, 브라우저, GPU 드라이버, 시스템 패키지까지 Python 잠금 파일이 고정하지는 않습니다.

    정리

    pyproject.toml은 허용 범위, uv.lock은 선택된 해결 결과, .venv는 현재 설치 결과입니다. requirements.txt도 생성 규칙과 설치 옵션을 엄격히 관리하면 재현 가능한 배포 입력이 될 수 있습니다. 중요한 것은 확장자가 아니라 정본, 생성 과정, 실패 조건을 팀이 합의하는 일입니다.

    자료 확인일은 2026년 9월 7일입니다. 본문은 uv 공식 프로젝트 구조와 잠금·동기화 문서를 기준으로 작성했습니다. 명령은 문서 기반 예시이며 이 글에서 설치 속도나 플랫폼별 동일성을 실측하지 않았습니다.

    728x90
    반응형
Designed by Tistory.