# How to Specify Python Versions in uv: Complete Syntax Guide

> Discover over 15 formats for specifying Python versions in uv. Learn syntax from simple strings like 3.12 to full distribution specs and filesystem paths.

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

---

**uv accepts over 15 distinct formats for specifying Python versions, ranging from simple strings like `3.12` to full distribution specifications like `cpython-3.12.3-macos-aarch64-none` and direct filesystem paths.**

The [astral-sh/uv](https://github.com/astral-sh/uv) toolchain provides a sophisticated version parsing system that normalizes diverse request formats into structured `PythonVersionRequest` objects. Whether you are creating virtual environments with `uv venv`, installing interpreters via `uv python install`, or running commands with `uv run`, understanding the available syntax for **specifying Python versions in uv** ensures precise control over interpreter selection.

## Simple Version Strings

The most common approach uses plain version numbers that match against installed or downloadable Python releases.

- **Major only**: `3` matches the latest Python 3 release available.
- **Major.minor**: `3.12` matches the latest patch of Python 3.12.
- **Major.minor.patch**: `3.12.3` requests an exact release.

```bash

# Create a venv with the latest Python 3.12 patch

uv venv --python 3.12

# Install a specific patch version

uv python install 3.11.9

```

## Version Specifiers and Ranges

For flexible constraints, uv accepts **PEP 440** version specifiers that define acceptable ranges rather than fixed versions.

```bash

# Install any Python version between 3.9 and 3.10

uv python install '>=3.9,<3.10'

# Create a venv with at least Python 3.12

uv venv --python '>=3.12'

```

These specifiers are parsed in [`crates/uv-python/src/python_version.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-python/src/python_version.rs) and normalized into internal constraint objects that drive the resolution logic.

## Implementation-Specific Requests

uv supports multiple Python implementations beyond CPython. You can request specific implementations using several syntax variants.

- **Implementation name only**: `cpython` or `cp` selects any available CPython version.
- **Implementation @ version**: `cpython@3.12` combines implementation and version.
- **Concatenated form**: `cpython3.12` or `cp312` for compact specification.

```bash

# Request CPython specifically

uv venv --python cpython@3.12

# Compact notation

uv python install cp313

```

## Build Variants: Free-Threaded and Debug Builds

Modern Python distributions include specialized builds identified by suffixes or explicit markers.

- **Short suffix**: Append `t` for free-threaded (no GIL) or `d` for debug builds.
  - `3.13t` requests free-threaded CPython 3.13.
  - `3.12.0d` requests a debug build.
- **Explicit variant**: Use the `+` syntax for clarity.
  - `3.13+freethreaded` or `3.14+gil` to explicitly request GIL-enabled or disabled builds.

```bash

# Free-threaded Python 3.13

uv python install 3.13t

# Debug build via explicit variant

uv venv --python 3.12+debug

```

## Full Distribution Specifications

For reproducible environments or CI pipelines, uv accepts complete distribution identifiers that specify platform and architecture.

The format follows: `implementation-version-os-arch-libc`

```bash

# Exact distribution specification

uv python install cpython-3.12.3-macos-aarch64-none

```

This format ensures you receive the exact binary used in production, avoiding subtle differences between patch releases or build configurations.

## Direct Executable Paths and Local Installations

When you need to use a Python interpreter that uv did not manage, specify the path directly.

- **Absolute path**: `/opt/homebrew/bin/python3`
- **Executable name**: `mypython3` (must exist on `PATH`)
- **Installation directory**: `/some/environment/` (directory containing the Python installation)

```bash

# Use a specific binary

uv venv --python /usr/local/bin/python3.10

# Reference by directory

uv run --python /opt/python3.12/ script.py

```

## How uv Parses Version Requests

Internally, uv normalizes all these formats through the `PythonVersion` type defined in [`crates/uv-python/src/python_version.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-python/src/python_version.rs). The parser converts textual requests into structured `PythonVersionRequest` objects that drive discovery, download, and selection logic.

According to the [Python versions concept documentation](https://github.com/astral-sh/uv/blob/main/docs/concepts/python-versions.md), uv evaluates version requests in the following priority:
1. Direct paths (filesystem checks)
2. Installed managed toolchains
3. Downloadable releases matching the specification

The resolver logic in [`crates/uv-resolver/src/python_requirement.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-resolver/src/python_requirement.rs) uses these parsed requests to enforce `requires-python` constraints during dependency resolution, while CLI commands in [`crates/uv-cli/src/commands/python.rs`](https://github.com/astral-sh/uv/blob/main/crates/uv-cli/src/commands/python.rs) handle the initial argument parsing.

## Summary

- **Simple versions** (`3.12`, `3.12.3`) target specific releases or the latest patch.
- **PEP 440 specifiers** (`>=3.12,<3.13`) define acceptable version ranges.
- **Implementation markers** (`cpython@3.12`, `cp312`) select specific Python flavors.
- **Build variants** (`3.13t`, `+debug`, `+freethreaded`) access specialized CPython builds.
- **Full distribution specs** (`cpython-3.12.3-macos-aarch64-none`) ensure exact binary reproducibility.
- **Direct paths** bypass uv's managed toolchain logic for custom installations.

## Frequently Asked Questions

### Can I use pyenv-style version strings like `3.12.0` in uv?

Yes, uv accepts standard semantic version strings including major-only (`3`), major-minor (`3.12`), and full patch (`3.12.3`) specifications. These are resolved against available managed toolchains or downloaded on demand. Unlike pyenv, uv does not require explicit installation before use; it can automatically fetch missing versions when running commands like `uv venv` or `uv run`.

### How do I request a free-threaded Python build without the GIL?

Use the short suffix `t` (e.g., `3.13t`) or the explicit variant syntax `+freethreaded` (e.g., `3.13+freethreaded`). Both formats instruct uv to download or select the experimental no-GIL build of CPython. Note that free-threaded builds are currently available for Python 3.13+ and require specific platform support.

### What is the difference between `cpython@3.12` and `cpython-3.12.3-macos-aarch64-none`?

The `@` syntax (`cpython@3.12`) specifies an implementation and version constraint, allowing uv to select any matching installed or downloadable release. The full distribution spec (`cpython-3.12.3-macos-aarch64-none`) is an exact platform-triple identifier that pins the operating system, architecture, and libc implementation, ensuring binary reproducibility across environments.

### Can I point uv to a Python installation it did not manage?

Yes, using direct path specifications. Provide an absolute path to the executable (`/usr/local/bin/python3`), an installation directory (`/opt/python3.12/`), or an executable name available on `PATH` (`python3.11`). When using direct paths, uv bypasses its managed toolchain logic and uses the specified interpreter directly, though features like automatic downloads will not apply.