# astral-sh/setup-uv: no @v10 tag, one cache key, and Python selection

> astral-sh/setup-uv has no @v10 tag to pin. Learn the refs that resolve, how enable-cache builds its key, and when you still need setup-python.

Source: https://latchkey.dev/learn/actions/astral-sh-setup-uv  
Updated: 2026-11-12

astral-sh/setup-uv installs uv, puts it on PATH and, on GitHub-hosted runners, saves the uv cache under a key built from the platform, the Python version and a hash of your dependency files. Since v8 it publishes no major tags, so `astral-sh/setup-uv@v10` does not resolve: pin a full version or a commit SHA.

Most setup-uv questions are one of three: why `@v8`, `@v9` or `@v10` fails to resolve, why the cache never restores on a branch or on a self-hosted runner, and whether you still need `actions/setup-python`. The answers are in the release notes and in a few lines of `src/utils/inputs.ts` and `src/cache/restore-cache.ts`.

The first stops a workflow before any step runs. setup-uv has published only full version tags since v8, so `@v10`, the form most other actions use, is not a ref GitHub can resolve. v10.3.3 is the current release, and everything below is read from that tag.

## Pinning: there is no @v10

v8.0.0 was the first immutable release, and its notes say the project will stop publishing major and minor tags because floating tags expose users to supply chain attacks. `@v7` and earlier still exist. Anything later fails before the job starts with: Unable to resolve action `astral-sh/setup-uv@v10`, unable to find version `v10`. That message is the title of issue #1091.

Pin the commit SHA with the version in a comment, and let Dependabot or Renovate bump it. Pin uv itself separately with `version`, as uv's own GitHub Actions guide recommends; otherwise the action looks for `required-version` in `uv.toml` or `pyproject.toml` and falls back to the latest uv.

```.github/workflows/ci.yml
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
  - uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
    with:
      version: "0.13.8"
  - run: uv sync --locked
  - run: uv run pytest
```

## Twenty-seven inputs, four you will touch

Twenty-seven inputs. The ones most workflows touch are `version`, `python-version`, `enable-cache` and `cache-dependency-glob`.

| Input | Default | What it does |
| --- | --- | --- |
| `version` | empty | uv version, `latest` or `latest-known`; empty reads `required-version`, then latest |
| `version-file` | empty | `uv.toml`, `pyproject.toml`, `.tool-versions`, `requirements.txt` or `uv.lock` |
| `resolution-strategy` | `highest` | `lowest` picks the oldest uv matching a range |
| `python-version` | empty | Sets `UV_PYTHON` for the rest of the job |
| `python-arch` | empty | Sets `UV_PYTHON_ARCH` |
| `activate-environment` | `false` | Creates a venv and puts it on PATH |
| `venv-path`, `no-project` | `.venv`, `false` | Where the venv goes; pass `--no-project` to `uv venv` |
| `working-directory` | workspace | Where config files are read and the venv is created |
| `checksum` | empty | Expected checksum of the uv download |
| `github-token` | `github.token` | Used only for GitHub Releases downloads |
| `enable-cache` | `auto` | Upload the uv cache to the Actions cache |
| `cache-dependency-glob` | requirements, constraints, `pyproject.toml`, `uv.lock`, `*.py.lock` | Files hashed into the key |
| `restore-cache`, `save-cache` | `true`, `auto` | Turn either half off; `auto` skips saving on `merge_group` |
| `cache-suffix` | empty | Appended to the key |
| `cache-local-path` | temp dir | Sets `UV_CACHE_DIR` unless it is already set |
| `prune-cache` | `false` | Run `uv cache prune --ci` before saving |
| `cache-python` | `false` | Also cache managed Python installs |
| `ignore-nothing-to-cache`, `ignore-empty-workdir` | `false` | Silence the empty-cache error and the empty-directory warning |
| `tool-dir`, `tool-bin-dir` | empty | Set `UV_TOOL_DIR` and `UV_TOOL_BIN_DIR` |
| `manifest-file`, `download-from-astral-mirror` | empty, `true` | Where versions and archives come from |
| `add-problem-matchers`, `quiet` | `true`, `false` | Annotations, and info-level log output |

> From `action.yml` at v10.3.3 (commit 68559e9), read 2026-11-12. Outputs: `uv-version`, `uv-path`, `uvx-path`, `cache-hit`, `cache-key`, `venv`, `python-version`, `python-runtime-id`, `python-cache-hit`.

## enable-cache, and the key it saves under

With `auto`, caching is on only when `RUNNER_ENVIRONMENT` is `github-hosted`. GitHub documents the other value as `self-hosted`, which covers every runner GitHub does not host, so on those `auto` means off and you set `enable-cache: true`. At v10.3.3 `auto` also turns caching off for tag pushes, `pull_request_target`, `workflow_run` and `release`, to keep those events from restoring a poisoned cache; v10.0.0 introduced the event list.

The key is `setup-uv-2-`, then the architecture, platform, OS name and version, and the Python version, then `-pruned` and `-py` when those options are on, then a hash of the files matching `cache-dependency-glob`, then your suffix. There are no restore keys, so a changed lockfile starts from an empty cache. The cache itself lives where `UV_CACHE_DIR` points, which the action sets to `/tmp/setup-uv-cache` on Linux and macOS unless you or your config already chose a path. Since v9 nothing is pruned before the save; `prune-cache: true` brings back `uv cache prune --ci`, which drops pre-built wheels and keeps the ones uv built from source. If the glob matches nothing, the action warns that the cache will never get invalidated, and the warning itself tells you to check that the repository was checked out first.

Two jobs with the same dependency files but different resolution strategies compute the same key and race to save it. The README's answer is a `cache-suffix` per strategy. On an exact hit the post step saves nothing. When caching is on and uv wrote nothing, the post step fails with `Cache path <path> does not exist on disk.` unless `ignore-nothing-to-cache` is set.

```.github/workflows/ci.yml
- uses: astral-sh/setup-uv@68559e99cc807c1eb7e9238fd43a15bba460eec2 # v10.3.3
    with:
      enable-cache: true
      cache-dependency-glob: uv.lock
      cache-suffix: ${{ matrix.resolution }}
```

## python-version and activate-environment

`python-version` exports `UV_PYTHON`, which overrides `.python-version` and the version in `pyproject.toml` for every later uv command; it is the documented way to drive a matrix. It does not activate anything. Until v6 it also created a venv; v6 moved that to `activate-environment`, which runs `uv venv`, adds the venv's bin directory to PATH and sets `VIRTUAL_ENV`.

The docs warn against activation for most workflows: a dependency that ships its own uv, such as hatch, then shadows the uv the action installed. `uv run` gives the same environment without touching PATH.

## v6 to v10: activation, tags, pruning, auto cache

| Release | Change |
| --- | --- |
| v6.0.0 | `activate-environment` replaces automatic venv activation; `working-directory` added; `pyproject-file` and `uv-file` removed |
| v7.0.0 | Runs on node24; respects an existing `UV_CACHE_DIR`; `server-url` removed |
| v8.0.0 | Immutable releases; no more major or minor tags; old manifest format removed |
| v9.0.0 | `prune-cache` default changed to `false` |
| v10.0.0 | `auto` cache off for sensitive events; `latest-known`; Python read from `.tool-versions` |

> From the GitHub release notes for each tag, read 2026-11-12.

## setup-uv or setup-python plus pip

They are not exclusive. uv's own guide shows both: `uv python install` after setup-uv, or setup-python before it, and says setup-python can be faster because GitHub keeps several Python versions on the runner image. The setup-uv README puts that at about a second.

The real difference is the cache. setup-python's pip cache stores pip's download cache with a restore key that falls back to an older entry; setup-uv stores the uv cache, including wheels uv built from source, on one key. [Caching pip and Poetry](/learn/speed/cache-pip-and-poetry-in-github-actions) measures what the pip cache is worth.

|  | setup-python `cache: pip` | setup-uv `enable-cache` |
| --- | --- | --- |
| Python comes from | The runner's tool cache or a download | The system, setup-python, or `uv python install` |
| What is cached | pip's download cache | The uv cache, optionally managed Pythons |
| Default key input | `**/requirements.txt` | requirements, constraints, `pyproject.toml`, `uv.lock` |
| Fallback on a key miss | Restore key without the hash | None |
| Default on non-GitHub runners | On when `cache` is set | Off with `auto` |

> setup-python keys from `src/cache-distributions/pip-cache.ts` at v7.1.0; setup-uv from `src/cache/restore-cache.ts` at v10.3.3. Read 2026-11-12.

## FAQ

### Why does astral-sh/setup-uv@v10 fail with unable to find version v10?

Because the tag does not exist. Since v8.0.0 the project publishes only full version tags such as `v10.3.3`, as a supply chain measure. Pin the full version or, better, the commit SHA with the version in a comment.

### Do I still need actions/setup-python alongside setup-uv?

No. uv can install Python with `uv python install`, or use the one on the runner. The setup-uv README notes that setup-python can be faster because the runner image already carries several versions, so either combination is reasonable.

### Why do I see No GitHub Actions cache found for key in setup-uv?

Because the key changed, usually after a dependency file changed, and there is no restore key to fall back to. The README calls it expected on the first run of a new key. If it appears on every run, check that checkout runs first and that `cache-dependency-glob` matches real files.

### Does setup-uv install my project or its dependencies automatically?

No. It installs uv and optionally sets the Python version and a venv. Run `uv sync --locked`, `uv pip install`, or `uv run`, which syncs before running, as a separate step.

## References

- [astral-sh/setup-uv README and action.yml at v10.3.3 (read 2026-11-12)](https://github.com/astral-sh/setup-uv/tree/v10.3.3)
- [astral-sh/setup-uv docs/caching.md](https://github.com/astral-sh/setup-uv/blob/v10.3.3/docs/caching.md)
- [astral-sh/setup-uv v8.0.0 release notes: no more major tags](https://github.com/astral-sh/setup-uv/releases/tag/v8.0.0)
- [uv docs: using uv in GitHub Actions](https://docs.astral.sh/uv/guides/integration/github/)
- [GitHub Docs: default environment variables, RUNNER_ENVIRONMENT](https://docs.github.com/en/actions/reference/workflows-and-actions/variables)

---

Latchkey runs CI/CD that repairs its own failures. Agent entry points: https://latchkey.dev/agent.txt, https://latchkey.dev/openapi.json, https://latchkey.dev/llms.txt
