pypa/manylinux wheel builds across Linux distributions
Python wheels that work on any linux (almost)
At a glance
- What is it?
- pypa/manylinux provides tagged Docker images for building portable Python wheels against selected glibc or musl baselines. It suits maintainers of packages containing compiled extensions who need repeatable Linux wheel environments rather than application deployment tools.
- Who is it for?
- Python extension maintainers should adopt pypa/manylinux when one build must support several Linux distributions and its architecture, glibc, and pip requirements are explicit. Projects that need only a containerized application or a guaranteed match to one modern distribution should use a purpose-built environment instead.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 1 day ago.
- What is it written in?
- Mainly Shell, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 7, 2026, and from our analysis. They are not legal advice.
Star history
- pypa/manylinux1,783 ★ · +3
| Repository | 2026-10-16 | 2026-11-07 |
|---|---|---|
| pypa/manylinux | 1.8k | 1.8k |
3 Stars in the last 22 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
Why pypa/manylinux builds wheels that travel between Linux systems
pypa/manylinux addresses a specific distribution problem: a Python package containing compiled code is not automatically portable between Linux environments. As the README explains, binaries built on one Linux distribution will generally work only on distributions of the same age or newer. Differences in the C library, its symbols, compiler output, and system libraries can therefore make a wheel fail even when its architecture matches.
The project supplies controlled Docker build environments and platform tags that communicate a wheel's Linux compatibility. The `manylinux_x_y` convention declares compatibility with systems based on `glibc>=x.y`. The related `musllinux_x_y` convention makes the corresponding claim for `musl>=x.y`. These tags let package indexes and installers select a wheel intended for the target environment.
This is aimed at maintainers who publish binary Python extensions as wheels, not at developers who merely want to run Python applications in Docker. The package author chooses a compatible build baseline, builds a wheel in the matching image, tags it, and can upload it to PyPI. The README states that compliant wheels can be uploaded with `twine` and installed with `pip`.
The practical value is repeatability. The images are uploaded to `quay.io` and tagged so that a build environment can be selected consistently. That does not guarantee that every binary package will work everywhere. It establishes the Linux platform boundary against which the wheel should be built.
The manylinux, PEP 600, and musllinux compatibility boundary
The tag families reflect changes in how Linux wheel compatibility was specified. According to the README, PEP 513 introduced `manylinux1_x86_64` and `manylinux1_i686` through builds on CentOS 5. PEP 571 followed with `manylinux2010_x86_64` and `manylinux2010_i686` through CentOS 6 builds. PEP 599 defined `manylinux2014` tags and CentOS 7 builds for several architectures.
PEP 600 changes the model. Instead of requiring a particular distribution or a fixed set of symbols, a `manylinux_x_y` wheel declares compatibility with any distribution based on `glibc>=x.y`. The project README describes this approach as designed to avoid tying future tags to one specific build distribution. PEP 656 adds the analogous `musllinux_x_y` naming for systems based on `musl>=x.y`.
That distinction matters during adoption. A wheel is not simply "for Linux." Its tag records the minimum library family and version represented by its build environment. A glibc-based tag does not establish compatibility with musl-based distributions, and the repository lists separate `musllinux_1_2` images for that purpose.
Older tags remain relevant to existing clients, but their underlying CentOS versions have reached end of life. The README records CentOS 5 EOL on March 31st, 2017, CentOS 6 EOL on November 30th, 2020, and CentOS 7 EOL on June 30th, 2024. Those dates describe the historical compatibility baselines. They do not mean that pypa/manylinux is unmaintained; the last repository push was on 2026-10-16.
Image coverage and the architecture decisions
Image selection is part of wheel compatibility. The README lists `manylinux_2_28` and `manylinux_2_34` images for `x86_64`, `i686`, `aarch64`, `ppc64le`, and `s390x`. For `armv7l`, it lists `manylinux_2_31` and `manylinux_2_35`. The `manylinux_2_39` entry currently names `aarch64` and `riscv64`, while `musllinux_1_2` covers `x86_64`, `i686`, `aarch64`, `ppc64le`, `s390x`, `armv7l`, and `riscv64`.
Not every image has the same maturity or operating-system base. The README labels the `manylinux_2_39` images for `aarch64` and `riscv64` as ALPHA and identifies AlmaLinux/RockyLinux 10 with GCC 14 as the toolchain. It describes them as expected to work with distributions using `glibc 2.39` or later, including the listed Debian, Ubuntu, Fedora, and CentOS/RHEL versions.
The `armv7l` images have a narrower construction. The README says the `manylinux_2_35` images are Ubuntu 22.04 based and available only for Debian derivatives because recent GCC toolchain builds compatible with a clean distribution installation are not available. Maintainers must also expect different package managers and package names there, rather than the RHEL-style assumptions used by other images.
A maintainer publishing for several CPU architectures needs one build decision per architecture. Selecting the most familiar image without checking its listed architecture can leave part of the wheel matrix unsupported.
Obtaining an image and completing a first wheel release
The repository directs users to Docker images uploaded to `quay.io`. Its README does not give an installation command, a `docker pull` example, or a complete build invocation.
For a first glibc build, select the image whose `manylinux_x_y` tag matches the oldest glibc environment that must run the wheel. The README gives the example image name `quay.io/pypa/manylinux_2_39_aarch64`. For a musl target, the separate image family uses `musllinux_1_2`; its architecture list differs from the glibc image list.
The real use is to build the project's binary wheel inside that selected image, confirm that its filename carries the matching platform tag, and upload it through the package publishing workflow. The README names `twine` as a possible upload tool and says compliant wheels can be installed with `pip`. It does not document the package-specific build invocation, so the correct build command depends on the extension and its own build system.
After publication, client-side compatibility depends on installer and Python versions. For `manylinux_x_y`, the table requires `pip >= 20.3` and lists compatible CPython sources beginning with 3.8.10, 3.9.5, or 3.10.0. A wheel cannot satisfy an older client that does not recognize its tag, regardless of whether its native code would run.
Where manylinux images fail as a general-purpose application environment
The strongest limitation is that compatibility is a contract with a selected minimum library baseline, not a promise of identical behavior on every Linux distribution. pypa/manylinux can control the build image and platform tag. It cannot remove an extension's dependency on an external library, conceal an unavailable CPU instruction, or make a glibc wheel valid on musl.
The alpha status of the `manylinux_2_39` images adds another boundary. The README explicitly marks the `aarch64` and `riscv64` images as ALPHA. A production release that needs a stable support claim should account for that label rather than treating every listed image as equally established.
The project is also the wrong tool for a source-only Python package with no compiled extension, or for a service that should reproduce one specific deployment image exactly. In those cases, the distribution portability problem does not exist, while application-level isolation and dependency management do. A normal application container can target a chosen operating system without adopting a cross-distribution wheel baseline.
Repository scripts and automation show that image creation and publication are operational parts of the project. The top-level layout includes `build.sh`, `deploy.sh`, `deploy_multiarch.sh`, Docker definitions, `noxfile.py`, tool directories, and requirement files. The README does not explain each script's options or rollback procedure, so those details cannot be inferred from their names.
How pypa/manylinux differs from pip and ordinary application containers
An alternative approach is to build a wheel in a container that mirrors one target Linux distribution. That method can produce a wheel for its own environment, but it does not by itself communicate a portable `manylinux` or `musllinux` baseline to installers. The project addresses both parts: a controlled build environment and standardized platform tags derived from it.
This differs from using `pip` alone. `pip` is the client that installs compatible wheels and must be new enough to recognize the relevant tag. The compatibility table requires `pip >= 20.3` for `manylinux_x_y`, `pip >= 19.3` for `manylinux2014`, and `pip >= 19.0` for `manylinux2010`. pypa/manylinux produces and classifies the artifact that such a client later selects.
It also differs from an ordinary application container. The latter bundles an application and its runtime dependencies for deployment. The manylinux images exist specifically to produce redistributable Python wheel artifacts that may be installed across multiple target systems. Their older libc baseline is useful for distribution reach, but it deliberately does not reproduce the newest operating system available.
The repository is MIT licensed. The README does not describe additional licensing conditions for built wheels or third-party packages, so maintainers must review those separately from the project's own license.
Editorial conclusion
Python extension maintainers should adopt pypa/manylinux when one build must support several Linux distributions and its architecture, glibc, and pip requirements are explicit. Projects that need only a containerized application or a guaranteed match to one modern distribution should use a purpose-built environment instead. Before adopting a particular image, verify its `manylinux` or `musllinux` tag against the oldest target system, select an image for that architecture, and confirm that the client `pip` version and embedded CPython version meet the compatibility table.
Frequently asked questions
What is pypa/manylinux used for?
It provides Docker images for building binary Python extension wheels that can run across compatible Linux distributions. It also documents the `manylinux_x_y` and `musllinux_x_y` platform-tag systems.
Which pypa/manylinux image supports riscv64?
The README lists `manylinux_2_39` and `musllinux_1_2` image coverage for `riscv64`. It labels the `manylinux_2_39` `riscv64` image ALPHA and identifies GCC 14 as its toolchain.
Can a manylinux wheel be installed on a musl-based Linux system?
The project defines separate `musllinux_x_y` tags for wheels built against `musl>=x.y`. A `manylinux_x_y` tag represents a glibc compatibility claim, so musl users require a wheel with the appropriate musllinux tag.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/pypa-manylinux)Star history chart for your README
[](https://hysenlabs.com/projects/pypa-manylinux)Was this useful?