
CI에서 ruff, ty, datasette 같은 Python 도구를 잠깐 실행해야 할 때가 있습니다. 이때 uvx tool-name은 도구를 프로젝트 의존성에 추가하지 않고 바로 실행할 수 있어 편합니다.1 다만 GitHub Actions에서는 한 가지를 더 고민해야 합니다. 실행할 때마다 도구 버전이 새로 해석되거나, 캐시가 기대대로 재사용되지 않으면 CI가 느려지고 결과도 예측하기 어려워질 수 있습니다.
핵심은 uvx를 “간편 실행 명령”으로만 보지 않고, 설치 방식·버전 고정·캐시 무효화 기준을 함께 설계하는 것입니다.
먼저 uv 설치와 버전을 고정한다
GitHub Actions에서 uv를 사용할 때는 공식 astral-sh/setup-uv 액션이 권장됩니다. 이 액션은 uv 설치, PATH 추가, 선택적 캐시 보존을 지원하며 uv가 지원하는 플랫폼에서 사용할 수 있습니다.2
CI에서는 uv 자체 버전도 고정하는 편이 좋습니다. setup-uv의 version 입력값으로 설치할 uv 버전을 지정할 수 있습니다.2 이렇게 하면 워크플로가 어느 날 갑자기 다른 uv 버전으로 실행되는 일을 줄일 수 있습니다.
- uses: astral-sh/setup-uv@v5
with:
version: "0.7.13"uvx로 실행하는 도구의 버전만 신경 쓰기 쉽지만, 실제로는 uv 버전과 도구 해석 기준이 함께 결과에 영향을 줍니다. 따라서 출발점은 uv 설치 방법을 표준화하고, uv 버전을 명시하는 것입니다.
uvx에는 별도의 캐시 기준이 필요할 수 있다
일반적인 uv 캐시는 setup-uv의 enable-cache: true로 보존할 수 있습니다.2
- uses: astral-sh/setup-uv@v5
with:
enable-cache: true수동으로 캐시를 관리한다면 actions/cache와 UV_CACHE_DIR를 함께 사용할 수 있습니다. 공식 예시의 캐시 키는 runner.os와 hashFiles('uv.lock') 같은 값을 포함합니다.2 uv pip 인터페이스를 쓴다면 uv.lock 대신 requirements.txt를 캐시 키에 쓰라는 팁도 제공됩니다.2
문제는 uvx로 단일 도구를 실행하는 워크플로입니다. 이런 경우에는 프로젝트에 uv.lock이나 requirements.txt를 만들지 않고 싶을 수 있습니다. 캐시 키에 넣을 “변경 기준”이 애매해지는 것입니다.
이때 사용할 수 있는 방법이 UV_EXCLUDE_NEWER를 기준값으로 삼는 방식입니다.
UV_EXCLUDE_NEWER를 캐시 키로 사용한다
워크플로 시작 시 다음처럼 환경 변수를 둡니다.
env:
UV_EXCLUDE_NEWER: "2026-07-12"UV_EXCLUDE_NEWER: "2026-07-12"를 설정하면 uvx tool-name은 해당 날짜를 기준으로 가능한 최신 버전을 선택합니다.3 즉, 매 실행마다 “오늘 기준 최신 버전”을 찾는 대신, 지정한 날짜 기준으로 도구 버전 해석을 제한합니다.
여기서 중요한 점은 이 날짜 값을 GitHub Actions 캐시 키에도 포함하는 것입니다.
- name: Cache uv
uses: actions/cache@v4
with:
path: ${{ env.UV_CACHE_DIR }}
key: uvx-${{ runner.os }}-${{ env.UV_EXCLUDE_NEWER }}이렇게 하면 날짜가 같을 때는 같은 기준으로 해석된 도구 캐시를 재사용할 수 있습니다. 도구를 업그레이드하고 싶을 때는 UV_EXCLUDE_NEWER 날짜를 바꾸면 됩니다. 날짜가 바뀌면 캐시 키도 바뀌므로 기존 캐시가 무효화되고, 새 기준으로 도구를 다시 받을 수 있습니다.3
이 방식의 장점은 단순합니다. 별도의 lockfile 없이도 “언제 도구를 새로 해석할지”를 한 줄의 날짜 값으로 관리할 수 있습니다.
캐시 최적화의 목적을 분명히 한다
uv 문서는 CI에서 uv cache prune --ci를 사용해 캐시 크기를 줄이는 방법을 안내합니다. 이 명령은 CI에 맞게 uv 캐시 크기를 줄이는 데 사용됩니다.2
다만 uvx 도구를 GitHub Actions에서 반복 실행하는 상황에서는 목표가 조금 다를 수 있습니다. 캐시 크기를 최소화하는 것보다, 같은 도구를 반복해서 내려받지 않고 예측 가능하게 재사용하는 것이 더 중요할 수 있습니다.
따라서 선택 기준은 다음처럼 정리할 수 있습니다.
uv 설치는
astral-sh/setup-uv로 표준화한다.uv 버전은
version입력값으로 고정한다.일반적인 프로젝트 의존성 캐시는
uv.lock또는requirements.txt를 기준으로 삼는다.lockfile 없이
uvx tool-name을 실행한다면UV_EXCLUDE_NEWER날짜를 캐시 키에 포함한다.도구 업그레이드는 날짜 값을 바꾸는 방식으로 명시적으로 수행한다.
결론적으로, GitHub Actions에서 uvx를 안정적으로 쓰려면 “간편 실행”과 “재현 가능한 CI” 사이의 균형을 잡아야 합니다. setup-uv로 설치를 통제하고, uv 버전을 고정하고, UV_EXCLUDE_NEWER를 캐시 키에 포함하면 작은 Python 도구 실행도 더 빠르고 예측 가능하게 운영할 수 있습니다.
참고
이 노트는 보도·비평·교육·연구 목적으로 작성되었습니다. 저작권 문의가 있으시면 에서 알려주세요.
