Where to Find the uv Resolver and Cache Source Code in the astral-sh/uv Repository
The uv resolver and cache source code is located in the crates/ directory of the astral-sh/uv repository, with the resolver implemented in the uv-resolver crate and caching functionality distributed across uv-cache-key, uv-cache-info, uv-fs, and uv-client.
The astral-sh/uv repository is organized as a Rust workspace containing multiple specialized crates under the crates/ directory. If you are looking to understand how uv performs dependency resolution or manages its aggressive caching strategy, you will need to examine specific crates dedicated to these concerns rather than a single monolithic source file.
Understanding the Crate Structure
The uv project follows a modular architecture where functionality is split into focused libraries. The crates/ directory at the repository root contains all sub-crates, each prefixed with uv- to indicate their purpose. When searching for the uv resolver source code or cache implementation, you should look for crates named uv-resolver, uv-cache-key, uv-cache-info, and uv-fs.
Locating the uv Resolver Source Code
The dependency resolution algorithm is implemented entirely within the uv-resolver crate. This crate contains the backtracking solver that determines compatible package versions across Python environments.
Core Resolver Implementation
The primary entry point for the resolver is crates/uv-resolver/src/lib.rs, which exports the Resolver struct and ResolverOptions. The resolution algorithm itself is implemented across several key files:
crates/uv-resolver/src/graph_ops.rs– Builds and mutates the dependency graph during resolutioncrates/uv-resolver/src/candidate_selector.rs– Chooses version candidates and handles backtracking when conflicts arisecrates/uv-resolver/src/flat_index.rs– Manages flat indexes (find-links) for direct URL dependencies
Resolution Strategies and Preferences
Advanced resolution behavior is controlled by:
crates/uv-resolver/src/fork_strategy.rs– Implements the "universal resolver" forking logic for handling Python version and platform markerscrates/uv-resolver/src/preferences.rs– Manages version preferences and existing lockfile constraintscrates/uv-resolver/src/marker.rs– Handles Python environment markers and platform selectors
Finding the uv Cache Source Code
Unlike the resolver, the caching subsystem is distributed across multiple crates, each handling a specific layer of the cache stack.
Cache Key Generation
The uv-cache-key crate at crates/uv-cache-key/src/cache_key.rs produces deterministic, reproducible cache keys for wheels, source distributions, and build artifacts. These keys ensure that identical inputs always map to the same cache location.
Cache Metadata and Storage
Two crates manage the physical and logical cache structure:
crates/uv-cache-info/src/cache_info.rs(uv-cache-infocrate) – Stores metadata about cached entries, including timestamps, hashes, and source URLs, plus expiration logiccrates/uv-fs/src/cachedir.rs(uv-fscrate) – Creates, reads, and prunes the on-disk cache directory (default~/.cache/uv)
Network and Distribution Caching
Higher-level caching for HTTP requests and Python packages:
crates/uv-client/src/cached_client.rs– Wrapsreqwestand stores HTTP responses in the cache, handling cache invalidation for PyPI JSON API and package downloadscrates/uv-distribution/src/index/cached_wheel.rs– Handles reading and writing cached wheel filescrates/uv-distribution-types/src/cached.rs– Type definitions for cached distribution metadata
CLI Cache Commands
The user-facing cache commands are implemented in the main uv binary crate:
crates/uv/src/commands/cache_dir.rs– Implementsuv cache dircrates/uv/src/commands/cache_clean.rs– Implementsuv cache cleancrates/uv/src/commands/cache_prune.rs– Implementsuv cache prunecrates/uv/src/commands/cache_size.rs– Implementsuv cache size
Practical Examples: Interacting with the Resolver and Cache
Below are practical examples demonstrating how the resolver and cache subsystems work in practice, both via CLI and programmatic Rust usage.
Resolving Dependencies via CLI
The uv lock command triggers the full resolution algorithm:
# Resolve requirements and write a lock file
uv lock --requirement requirements.txt
Internally, this creates a Resolver instance from uv_resolver::Resolver and calls resolve(), which traverses graph_ops.rs and candidate_selector.rs to produce a concrete dependency graph.
Inspecting Cache State
Monitor cache utilization using built-in commands:
uv cache size # Displays total cache size
uv cache prune --dry-run # Lists entries eligible for removal
These commands walk the directory structure created by uv_fs::cachedir::CacheDir, aggregate file sizes, and respect expiration timestamps from uv_cache_info::CacheInfo.
Bypassing Cache for Fresh Downloads
Force network refresh with:
uv pip install requests --refresh
The --refresh flag instructs uv_client::cached_client::CachedClient to ignore stored HTTP responses and re-download the wheel from PyPI.
Using the Resolver Programmatically
For Rust developers integrating uv's resolver:
use uv_resolver::{Resolver, ResolverOptions, Requirements};
use uv_types::Requirement;
let req = Requirement::from_str("requests==2.31.0")?;
let reqs = Requirements::from_requirements(vec![req]);
let resolver = Resolver::new(ResolverOptions::default());
let resolved = resolver.resolve(&reqs)?;
println!("Resolved version: {}", resolved[0].version);
This example pulls in uv-resolver directly, utilizing the algorithms defined in src/graph_ops.rs and src/candidate_selector.rs.
Programmatic Cache Access
Demonstrating cache key generation and lookup:
use uv_cache_key::CacheKey;
use uv_fs::cachedir::CacheDir;
use std::path::PathBuf;
let key = CacheKey::new("requests", "2.31.0", "cp311-cp311-manylinux_2_17_x86_64.whl");
let cache_dir = CacheDir::default(); // Resolves to $XDG_CACHE_HOME/uv
let cached_path: PathBuf = cache_dir.path().join(key.to_path());
if cached_path.exists() {
println!("Found cached wheel at {}", cached_path.display());
}
This shows how uv-cache-key generates deterministic identifiers and how uv-fs::cachedir resolves the physical storage location.
Summary
- The uv resolver source code lives in the
uv-resolvercrate undercrates/uv-resolver/src/, with core logic inlib.rs,graph_ops.rs, andcandidate_selector.rs. - The uv cache source code is distributed across multiple crates:
uv-cache-keyfor key generation,uv-cache-infofor metadata,uv-fsfor directory operations, anduv-clientfor HTTP caching. - The main
uvbinary crate implements CLI commands likeuv cache dir,uv cache prune, anduv cache sizeincrates/uv/src/commands/cache_*.rs. - All components follow a modular Rust architecture under the top-level
crates/directory in the astral-sh/uv repository.
Frequently Asked Questions
Where is the uv resolver algorithm implemented?
The uv resolver algorithm is implemented in the uv-resolver crate located at crates/uv-resolver/src/. The entry point is lib.rs, which exports the Resolver struct. The core resolution logic resides in graph_ops.rs (dependency graph construction), candidate_selector.rs (version selection and backtracking), and fork_strategy.rs (handling Python version markers). This crate implements the backtracking solver that determines compatible package versions across different Python environments and platforms.
How does uv handle cache key generation?
Cache key generation is handled by the uv-cache-key crate in crates/uv-cache-key/src/cache_key.rs. This crate produces deterministic, reproducible cache keys for wheels, source distributions, and build artifacts. The keys incorporate package name, version, platform tags, and build requirements to ensure that identical inputs always map to the same cache location. This deterministic approach allows uv to safely reuse cached artifacts across different projects and virtual environments without collisions.
What commands can I use to manage the uv cache?
The uv CLI provides several commands to inspect and manage the cache, implemented in crates/uv/src/commands/. Use uv cache dir to display the cache directory location, uv cache size to check total disk usage, and uv cache prune to remove unused entries. The --dry-run flag with cache prune shows what would be deleted without removing files. To bypass the cache entirely for a specific operation, use the --refresh flag with install commands, which forces uv-client to re-download packages from PyPI.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →