# How uv Automatically Cleans Up Old Cache Entries: A Complete Guide to `uv cache prune`

> Learn how uv automatically cleans up old cache entries with uv cache prune. Safely remove unused artifacts and keep your cache lean. A complete guide.

- Repository: [Astral/uv](https://github.com/astral-sh/uv)
- Tags: how-to-guide
- Published: 2026-03-01

---

**Yes, uv can automatically clean up old cache entries using the built-in `uv cache prune` command, which safely removes unused artifacts while preserving entries still referenced by active projects or the current uv version.**

The uv package manager from astral-sh/uv maintains an aggressive caching strategy to speed up dependency resolution and installation. Over time, this cache can grow to include stale source distributions, outdated wheels, and unzipped archives that are no longer referenced by your projects. Understanding how uv automatically cleans up these old cache entries helps you manage disk space efficiently, especially in CI/CD environments.

## What Gets Removed When You Prune the uv Cache

The `uv cache prune` command targets specific categories of unreachable cache entries. According to the implementation in [`crates/uv-cache/src/lib.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-cache/src/lib.rs), the pruning process identifies and removes artifacts that have no valid references from the current cache version or active virtual environments.

### Unused Top-Level Directories and Archives

When you run `uv cache prune`, the command removes:

- **Stale top-level directories** containing old wheel or source-distribution buckets that are no longer indexed
- **Orphaned source-distribution revisions** that have been superseded by newer builds
- **Unzipped archives** that were extracted for installation but are no longer referenced by any active environment
- **Unused cached virtual-environment directories** that were created for intermediate operations but never linked to a project

### CI Mode Optimizations

The `--ci` flag modifies the pruning behavior for continuous integration environments. As implemented in [`crates/uv/src/commands/cache_prune.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv/src/commands/cache_prune.rs), CI mode:

- **Drops pre-built wheels** that were downloaded from package indexes, keeping only wheels that were built from source locally
- **Removes unzipped source trees** while preserving the original archive files
- **Retains source-built wheels** that are expensive to rebuild, ensuring subsequent CI runs can still benefit from cached compilations

## How `uv cache prune` Works Internally

Understanding the internal mechanics of cache pruning helps you use the command effectively and troubleshoot potential issues.

### Cache Discovery and Locking

The pruning process begins with cache location resolution. According to [`docs/concepts/cache.md`](https://github.com/astral-sh/uv/blob/main/docs/concepts/cache.md), uv determines the cache directory using the standard platform conventions:

- **Linux/macOS**: `$XDG_CACHE_HOME/uv` (or `~/.cache/uv` if `XDG_CACHE_HOME` is unset)
- **Windows**: `%LOCALAPPDATA%\uv\cache`

Once located, the command acquires an **exclusive lock** on the cache directory. As shown in [`crates/uv/src/commands/cache_prune.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv/src/commands/cache_prune.rs) (lines 29-42), the implementation waits up to 5 minutes for the lock by default. If another uv process holds the lock, the command either waits or exits immediately if the `--force` flag is provided.

### The Pruning Algorithm

The actual cleanup follows a two-phase approach:

1. **Source Distribution Pruning**: The command calls `uv_distribution::prune(&cache)` to clean the tightly-coupled source-distribution bucket, removing stale revisions and build artifacts that are no longer indexed (lines 52-55 in [`cache_prune.rs`](https://github.com/astral-sh/uv/blob/main/cache_prune.rs)).

2. **General Bucket Pruning**: The command delegates to `Cache::prune(ci)` defined in [`crates/uv-cache/src/lib.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-cache/src/lib.rs) (lines 582-586). This method walks through all cache buckets—wheels, archives, and virtual environments—and deletes any entries not referenced by the current cache schema version or active project metadata.

### Safety Guarantees

The pruning implementation includes several safety mechanisms to prevent data loss:

- **Reference Checking**: Before deletion, the system verifies that no active virtual environment or lockfile references the cache entry. Only **orphaned** entries are removed.
- **Version Compatibility**: The cache schema version is checked to ensure that entries created by newer uv versions are not accidentally deleted by older clients.
- **Atomic Operations**: The exclusive lock ensures that no other uv process can modify the cache during pruning, preventing race conditions that could leave the cache in an inconsistent state.

## Practical Usage Patterns for uv Cache Pruning

Integrating `uv cache prune` into your workflow requires understanding when and how to run it for maximum benefit.

### Manual Cleanup

For local development, run periodic cleanup to reclaim disk space:

```bash

# Safe, standard pruning - removes only unreachable entries

uv cache prune

```

This command is safe to run at any time and will only remove entries that are no longer referenced by your current projects. The output will display the number of files, directories, and total bytes removed.

### CI Pipeline Integration

In continuous integration environments, cache pruning is essential for controlling artifact sizes. The `--ci` flag optimizes the cache for ephemeral CI runners:

```bash

# CI-optimized pruning - keeps source-built wheels, drops pre-built wheels

uv cache prune --ci

```

When used in a GitHub Actions workflow, this pattern reduces the cache size significantly while preserving expensive-to-rebuild wheels:

```yaml
steps:
  - uses: astral-sh/setup-uv@v2
  - name: Restore cache
    uses: actions/cache@v4
    with:
      path: ~/.cache/uv
      key: ${{ runner.os }}-uv-${{ hashFiles('**/pyproject.toml') }}
  - name: Install dependencies
    run: uv sync
  - name: Prune cache after build (reduces artifact size)
    run: uv cache prune --ci

```

### Force Pruning Without Waiting

If you encounter lock contention or need immediate cleanup in automated scripts, use the `--force` flag:

```bash

# Skip the 5-minute lock wait, fail immediately if cache is in use

uv cache prune --force

```

This is useful in containerized environments where you control the execution context and can guarantee no other uv processes are running.

## Summary

- **uv automatically cleans up old cache entries** through the `uv cache prune` command, which removes orphaned artifacts while preserving active dependencies.
- The command targets **unused top-level directories, stale source distributions, unzipped archives, and orphaned virtual environments** identified in [`crates/uv-cache/src/lib.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-cache/src/lib.rs).
- **CI mode** (`--ci`) optimizes cache size for ephemeral runners by dropping pre-built wheels while keeping expensive source-built wheels.
- The implementation uses **exclusive locking** (5-minute timeout by default) and reference checking to ensure only truly unused entries are deleted, making the operation safe for production use.

## Frequently Asked Questions

### Does uv automatically clean up old cache entries without running a command?

No, uv does not automatically prune the cache in the background or during regular operations. You must explicitly run `uv cache prune` to remove old entries. The cache grows monotonically during normal usage until you manually trigger cleanup, which is why periodic pruning is recommended for long-running development environments.

### Is it safe to run `uv cache prune` while other uv processes are active?

It is generally safe because the command acquires an exclusive lock on the cache directory before modifying anything. If another uv process holds the lock, `uv cache prune` will wait up to 5 minutes by default. However, to avoid delays or potential conflicts, it is best practice to run the prune command when no other uv operations are active, or use `--force` only when you can guarantee exclusive access.

### What is the difference between `uv cache prune` and `uv cache prune --ci`?

The standard `uv cache prune` removes all cache entries not referenced by the current uv version or active projects, including unused wheels, source distributions, and archives. The `--ci` flag modifies this behavior specifically for continuous integration environments: it additionally drops pre-built wheels downloaded from package indexes and removes unzipped source trees, while preserving wheels that were built from source locally. This reduces cache size significantly for ephemeral CI runners where pre-built wheels can be re-downloaded quickly.

### How can I see what `uv cache prune` will delete before it runs?

Currently, uv does not provide a dry-run or preview mode for `uv cache prune`. The command executes the deletion immediately after acquiring the cache lock. However, the command outputs a summary to stderr after completion, reporting the number of files, directories, and total bytes removed. To monitor cache growth before pruning, you can inspect the cache directory size manually using standard tools like `du -sh ~/.cache/uv` on Linux/macOS or checking `%LOCALAPPDATA%\uv\cache` on Windows.