Wheel
A wheel is a built distribution format for Python packages, defined by PEP 427. It uses the .whl extension and is a ZIP archive containing the package’s code and metadata, ready for direct installation. Wheels are one of two standard distribution formats on PyPI, the other being sdist.
Why Wheels Matter
Installing from an sdist requires executing arbitrary build code (setup.py, a build backend, etc.) to produce installable artifacts. Wheels skip that step entirely. Because they are pre-built, the installer copies files into place without invoking a compiler or running any build logic.
This has two practical consequences. Installs are faster, often by an order of magnitude for packages with C extensions. And environments without a C compiler – such as minimal Docker images or CI runners – can still install compiled packages, as long as a compatible wheel exists on PyPI.
When pip or uv resolves a package, it prefers the wheel over the sdist when one is available.
Filename Convention
Wheel filenames encode compatibility information using a structured naming scheme:
{distribution}-{version}(-{build tag})-{python tag}-{abi tag}-{platform tag}.whlA few examples:
| Filename | Meaning |
|---|---|
requests-2.31.0-py3-none-any.whl | Pure Python, no compiled code, runs on any platform |
numpy-1.26.0-cp312-cp312-manylinux_2_17_x86_64.whl | Compiled C extensions, CPython 3.12, Linux x86_64 |
The tags break down as follows:
- Python tag (
py3,cp312): the Python implementation and version the wheel supports.py3means any Python 3 interpreter;cp312means CPython 3.12 specifically. - ABI tag (
none,cp312): the Application Binary Interface.nonemeans no ABI dependency; a CPython-specific tag indicates compiled extensions linked against that version’s ABI. - Platform tag (
any,manylinux_2_17_x86_64,win_amd64): the operating system and architecture.anymeans platform-independent.
Wheel vs sdist
| Wheel | sdist | |
|---|---|---|
| Format | ZIP archive (.whl) | Compressed tarball (.tar.gz) |
| Contents | Pre-built code and metadata | Source code and build instructions |
| Install speed | Fast (copy files into place) | Slower (must run build step) |
| Compiler required | No | Yes, for packages with C extensions |
Most packages on PyPI publish both formats. The sdist serves as a fallback for platforms where no matching wheel exists, and as an archival source-code snapshot.
Building Wheels
The standard way to build a wheel is through a build frontend that invokes the project’s build backend:
# Using uv
uv build
# Using the build package
python -m buildBoth commands read the [build-system] table in pyproject.toml and delegate to the configured backend. Common backends that produce wheels include setuptools, hatchling, and flit.
Built artifacts are placed in the dist/ directory by default.
Platform Wheels
Pure Python packages produce universal wheels tagged py3-none-any, which work on any platform and Python 3 interpreter. Packages with compiled extensions (C, C++, Cython, Rust) produce platform-specific wheels tied to a particular OS, architecture, and Python version.
On Linux, the manylinux standard defines a set of baseline system libraries that a wheel can depend on. Wheels built to this standard (e.g., manylinux_2_17_x86_64) are portable across most Linux distributions. macOS and Windows wheels use their own platform tags (macosx_11_0_arm64, win_amd64).
Package maintainers who need to publish platform wheels for multiple targets often use cibuildwheel to automate builds across operating systems and Python versions in CI.