# virtualenv: the environment builder that ships almost no instructions

> The PyPA tool every Python project leans on has a README made of badges and links, so the real story sits in its packaging metadata, its pinned dependencies and three releases in three days that were almost entirely about supply chain metadata.

**pypa/virtualenv** — Virtual Python Environment builder

- Repository: https://github.com/pypa/virtualenv
- Website: https://virtualenv.pypa.io
- Stars: 5,055 · Forks: 1,130
- Language: Python
- License: MIT
- Published: 2026-10-07 · Updated: 2026-10-07 · Language: en
- Canonical page: https://hysenlabs.com/projects/pypa-virtualenv

## A README that is almost entirely badges and outbound links

The README for pypa/virtualenv opens with a wall of shields.io badges for PyPI version, implementation, Python versions, Discord, monthly downloads, licence, the check workflow, the OpenSSF Scorecard and OpenSSF Best Practices. Then it delivers a single sentence of description, a tool for creating isolated virtual python environments, and seven links. The last link is a code of conduct pointing at the PSF document.

That is the entire README. There is no install command, no usage example, no flag list, and no code fence of any kind, so anyone arriving from the repository page has to click through to the documentation site to learn anything at all.

What the repository itself shows is a much larger project than that README implies. The top level holds `src/`, `tests/`, `tasks/`, `docs/`, `hatch_build.py`, `tox.toml`, `pyproject.toml`, `scorecard.yml`, `_typos.toml`, a `.pre-commit-config.yaml` and a `THIRD-PARTY-NOTICES.md`. The Cython topic sits alongside the Python ones, and the presence of a fuzz-instrumented continuous integration line in the recent changelog entries suggests a compiled extension under test. A README that short is a deliberate choice by a project whose users already know what it is; it is not evidence of a small or abandoned tool.

## What the packaging metadata actually promises

Because the README carries no specifications, `pyproject.toml` becomes the real product description. It declares the name `virtualenv`, the summary Virtual Python Environment builder, keywords of environments, isolated and virtual, the MIT licence with `LICENSE` and `THIRD-PARTY-NOTICES.md` both listed as licence files, and `requires-python = ">=3.9"`. The version is declared dynamic, filled in at build time by hatch-vcs rather than written into the file.

The classifiers are more informative than the summary line. The package declares itself at Development Status 5, Production/Stable, and claims interpreter coverage from Python 3.9 all the way through 3.15, across MacOS X, Windows and POSIX, for both CPython and PyPy. Since 3.15 is a version ahead of what most environments ship today, the classifier is a forward-looking statement of intent rather than a description of what is exercised today.

Two maintainers are named in the file, Bernat Gabor and Rahul Devikar. That is worth noting on its own: build tooling for Python sits in the same maintainer hands for long stretches, and the release history confirms it, with nearly every listed change authored by the first name.

## Installing from PyPI and reading the dependency set

The README routes installation to its documentation rather than spelling it out, and the package it points at is the PyPI distribution named `virtualenv`. Installing it into a base interpreter is the normal first step.

```bash
pip install virtualenv
```

The dependency list is where the real design decisions live, and it is unusually explicit about interpreter-dependent floors.

```toml
requires-python = ">=3.9"
dependencies = [
  "distlib>=0.3.7,<1",
  "filelock>=3.16.1,<=3.19.1; python_version<'3.10'",
  "filelock>=3.24.2,<5; python_version>='3.10'",
  "platformdirs>=3.9.1,<5",
  "python-discovery>=1.6",
 ]
```

Two things stand out. First, `filelock` is pinned twice with different ceilings depending on whether the interpreter is older or newer than 3.10, so a machine running Python 3.9 and a machine running 3.12 do not install the same set. Second, `python-discovery` appears as a hard requirement rather than something bundled, which means the tool that locates Python interpreters on the system depends on an external package doing that job well.

The build system is hatchling with hatch-vcs, and the hatchling version itself is split on the same 3.10 boundary. This is the level of care you want in a package that other people's tooling shells out to, and it is entirely invisible from the README.

## Where it sits against the standard library venv

The most common question about this tool is how it differs from `venv`, the module that ships inside the standard library. The distinction that survives scrutiny is distribution. `venv` is available the moment you have a Python interpreter, with no install step, while virtualenv is a PyPI package with its own dependency set and its own release cadence. Anything that needs to pin, mirror or audit the environment builder, including continuous integration images, depends on virtualenv being a package it can control.

This repository's own metadata supports the second half of that story. The topics list includes `jython`, `pypy` and `pypy3`, which advertises support across implementations beyond CPython. The classifiers, by contrast, name only CPython and PyPy. Those two facts sit awkwardly next to each other, and rather than pick one, the useful reading is that the topic list reflects the breadth the project has historically worked toward while the classifier list reflects what it is willing to assert as supported on a given release. If implementation support matters to you, the classifier is the conservative signal.

Licensing is not a complication. MIT applies, and the project goes out of its way to ship third party notices as a first-class file rather than burying them, which is the kind of hygiene you want from something installed by nearly every Python project on the machine.

## Source layout, testing harness and supply chain checks

The repository splits into the pieces you would expect from a mature Python package: implementation under `src/`, a separate `tests/` tree, `tasks/` for development automation, `docs/` for the published manual, and `tox.toml` driving the test matrix. The docs are what the README assumes you already read, which is why a first-time visitor finds the project underdocumented at its front door and reasonably documented once they follow one link.

Two configuration files describe how the project holds itself to account. `scorecard.yml` configures the OpenSSF Scorecard, and the README carries both the Scorecard badge and an OpenSSF Best Practices badge. The recent changelog entries add detail: fuzz targets instrumented in continuous integration, rejection of unrelated GraalPy failures so they do not mask real regressions, and a check that newly added wheels are verified for age before use.

Taken together, these say something specific about how this release line is being worked on. Nobody is adding user-facing commands to the changelog. The effort is going into making the published artifacts trustworthy.

## Three releases in three days, all about provenance

The release list is unusual enough to read closely. Version 21.9.0 was published on 2026-09-20 and contains exactly two entries, both about the SBOM: adding a timestamp and generator metadata, and making the embedded SBOM exhaustive. Version 21.9.1 followed the next day with notice formatting, preservation of partial publications when a release fails partway, reconciliation of security incident response documentation, GraalPy filtering in continuous integration, fuzz instrumentation, wheel age checks and SBOM reproducibility.

Version 21.10.0 landed on 2026-09-22, the same day as the last push recorded for the repository. It allows `filelock` 4.x on Python 3.10 and later, which matches the dependency ceiling widening in the packaging metadata, and it adds the ability to identify vendored packages inside the SBOM. It also rejects batch mode paths that quoting has altered, which is the kind of bug that would corrupt an environment silently, and it isolates generation credentials.

The pattern is consistent enough to name: this project currently spends its release effort on proving what it built. If your concern about environment builders is supply chain rather than speed, that is the axis on which this one is moving, and the changelog is the place to watch it. The last push was on 2026-09-22 and the repository is not archived.

## Conclusion

virtualenv is one of those projects you install without reading and depend on every day, and this article's honest conclusion is that the thin README is not a warning sign. The packaging metadata is precise, the interpreter floor moves with the Python version you run, and the current release line is spending its effort on an embedded SBOM, artifact verification and reproducible notices rather than on new user-facing commands. Adopt it as the default for any project that declares it, and adopt it deliberately for anything touching Python 3.9 or older where the dependency pins differ. Do not reach for it when you want to understand what a dependency tree does, because that is `pip`'s job, not this one's. Start at virtualenv.pypa.io for the install page, then read pyproject.toml in this repository to see the exact floors you are inheriting.

## FAQ

### What is virtualenv for?

It builds isolated Python environments. Each one gets its own directory with its own installed packages, so two projects on the same machine can require incompatible versions of the same library without interfering with each other. The project describes itself as a tool for creating isolated virtual python environments, and its packaging metadata categorises it under development libraries, testing and general utilities.

### What is the difference between venv and virtualenv?

`venv` is a module in the standard library, available as soon as you have an interpreter. virtualenv is a PyPI package with its own dependencies, including distlib, filelock, platformdirs and python-discovery, and its own release schedule. That difference is what lets an automated system pin, mirror or audit the environment builder, which is why tooling installed by other Python packages tends to reach for virtualenv rather than the standard library module.

### How do I turn on virtual env?

The README for this repository does not cover activation, and it points to virtualenv.pypa.io for anything beyond a one line description. Activation scripts are generated into the environment directory itself, so the concrete instructions live in that documentation rather than in the repository. This project deliberately keeps its README to badges and links, so expect to leave GitHub for the operational details.

## Sources

- [License: MIT](https://github.com/pypa/virtualenv/blob/main/LICENSE)
- [Project website](https://virtualenv.pypa.io)
- [pypa/virtualenv on GitHub](https://github.com/pypa/virtualenv)
- [README](https://github.com/pypa/virtualenv/blob/main/README.md)
- [Releases](https://github.com/pypa/virtualenv/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/pypa-virtualenv
