Open-source project
pyenv/pyenv-virtualenv avatar
pyenv/pyenv-virtualenv

pyenv-virtualenv: Managing Python Environments as a pyenv Plugin

a pyenv plugin to manage virtualenv (a.k.a. python-virtualenv)

6,728 stars427 forksShellMIT

At a glance

What is it?
A pyenv plugin that creates and activates virtualenvs and conda environments under pyenv's versions directory. It suits UNIX-like setups that already use pyenv, and it is not a Windows tool.
Who is it for?
Adopt pyenv-virtualenv if you already run pyenv on a UNIX-like system and want virtualenv creation, activation and deletion to sit beside your Python version management; the README's `pyenv virtualenv-init -` hook is what makes directory-based activation work. Skip it if you are on Windows, since the README targets UNIX-like systems, or if you want a dependency and packaging manager rather than environment plumbing.
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 154 days 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 September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The gap pyenv-virtualenv fills between Python versions and project dependencies

pyenv answers one question: which Python interpreter runs in this directory. It does not answer the second question, which packages are installed for that interpreter. Without a second tool, installing a project's dependencies into a pyenv-managed interpreter pollutes that interpreter for every other project using it.

pyenv-virtualenv is a pyenv plugin, written in Shell, that adds virtualenv and conda environment management to pyenv itself. The README describes it as providing "features to manage virtualenvs and conda environments for Python on UNIX-like systems." Because it is a plugin rather than a separate command-line tool, the environments it creates live under pyenv's own versions directory, and pyenv's version selection machinery can point at them.

That placement is the whole point. A virtualenv becomes just another entry that pyenv can select, which means `pyenv local`, `.python-version` files and shell activation all keep working, with no second tool tracking which environment belongs to which interpreter.

The audience is narrow and specific: developers on macOS, Linux or WSL who already use pyenv and want their environments registered in the same place as their interpreters. If you do not use pyenv, this plugin has nothing to attach to.

How environments end up inside pyenv's versions directory

The mechanism is a naming and layout convention. When you run `pyenv virtualenv 2.7.10 my-virtual-env-2.7.10`, the README says the result is a virtualenv based on Python 2.7.10, created under `$(pyenv root)/versions` in a folder named `my-virtual-env-2.7.10`. In other words, the environment is not stored in a project directory. It is stored as a sibling of the interpreters pyenv manages.

`pyenv virtualenv` forwards its options to whichever command actually builds the environment: `conda`, `virtualenv`, or `python -m venv`. The README states the plugin uses `python -m venv` when that is available and the `virtualenv` command is not. So the plugin is a dispatcher over three backends, and the backend determines what the resulting environment contains.

Listing reveals the layout's quirk. `pyenv virtualenvs` prints two entries per environment, one short and one long, and the README explains that "the shorter one is just a symlink." For a 3.4.3-based environment named `venv34`, the list shows both `3.4.3/envs/venv34` and `venv34`, the latter marked with an asterisk when active. Conda environments appear in the same list, for example `miniconda3-3.9.1/envs/myenv`, which is why the listing is the single place to look when you are unsure what exists.

Activation is driven by `.python-version`. With `eval "$(pyenv virtualenv-init -)"` configured, the plugin activates and deactivates environments automatically as you enter and leave directories whose `.python-version` file names a valid environment. The README notes those files are normally created with `pyenv local`.

Installing pyenv-virtualenv as a plugin and creating a first environment

The primary install path is cloning the repository into pyenv's plugins directory. The README warns that if pyenv is installed in a non-standard location, the clone must go into the plugins directory of wherever pyenv actually lives.

bash
git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv

For the Fish shell the README gives the equivalent form with Fish command substitution:

fish
git clone https://github.com/pyenv/pyenv-virtualenv.git (pyenv root)/plugins/pyenv-virtualenv

Auto-activation is optional but is the feature most people want. It is enabled by adding one line to your shell startup file, `~/.bashrc` for Bash, `~/.zshrc` for Zsh, or `~/.config/fish/config.fish` for Fish.

bash
echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bashrc

After that, restart the shell so the plugin is loaded:

bash
exec "$SHELL"

With the plugin in place, create an environment from a pyenv-managed interpreter by naming both the version and the environment:

sh
pyenv virtualenv 2.7.10 my-virtual-env-2.7.10

If exactly one argument is given, the README states the environment is created from the current pyenv Python version, so `pyenv virtualenv venv34` under a 3.4.3 interpreter produces an environment named `venv34`. Run `pyenv virtualenvs` to confirm it appears in the list.

Deleting environments and the two ways to do it

Removal has three documented routes, and they are not equivalent in what they touch. Removing the directories under `$(pyenv root)/versions` and `$(pyenv root)/versions/{version}/envs` deletes the environment at the filesystem level. The README also gives `pyenv uninstall my-virtual-env` and a plugin-specific command:

sh
pyenv virtualenv-delete my-virtual-env

The existence of both `pyenv uninstall` and `pyenv virtualenv-delete` is worth noting. The README presents them as alternatives without explaining when to prefer one, and it does not document rollback or recovery if you delete an environment that a project still references. If a `.python-version` file in a project names an environment you removed, the README does not describe what the shell hook does next. Treat deletion as destructive and check `pyenv virtualenvs` before and after.

Where pyenv-virtualenv is the wrong tool

The README scopes the project to UNIX-like systems, and the installation section adds a WSL note recommending `git config --global core.autocrlf input` to avoid script execution errors from line endings. There is no documented Windows installation path. If Windows is your platform, this is not the tool, and questions about installing it there are not answered by the repository.

A second limitation is conceptual. pyenv-virtualenv manages environments; it does not resolve, lock or record dependency sets. There is no lockfile concept in the README, no dependency resolver, and no packaging workflow. If your problem is reproducible dependency graphs across machines, environment creation is only the first step and the plugin does not take the later ones.

Third, the plugin depends on pyenv being correctly installed and initialized. The README's activation instructions assume pyenv's own shell setup steps have been completed, and the auto-activation feature exists only if `pyenv virtualenv-init -` is evaluated in your shell. When activation fails, the failure usually lives in shell configuration rather than in the plugin, and the README does not provide a troubleshooting section for that case.

How it compares with venv, virtualenv and conda

The nearest alternative is the standard library's `venv` module, available for CPython 3.3 and newer, which the README calls the successor of `virtualenv`. The difference is registration, not creation. `python -m venv` creates an environment wherever you point it, and nothing outside your shell remembers it exists. pyenv-virtualenv creates the environment under pyenv's versions directory and makes it selectable through pyenv's version mechanism, including `.python-version` files. The plugin even uses `python -m venv` as a backend when the `virtualenv` command is absent, so the two are not rivals at the level of environment construction; they differ in whether pyenv knows about the result.

Conda is handled differently again. The README shows conda environments being created with `conda create` in the usual manner and then used through `pyenv activate` and `pyenv deactivate`. So pyenv-virtualenv does not replace conda's own creation command; it surfaces conda environments in `pyenv virtualenvs` and lets pyenv's activation commands reach them. For a Miniconda-based interpreter, `conda env list` and `pyenv virtualenvs` describe overlapping state.

For users of virtualenvwrapper, the README explicitly points to a separate project, pyenv-virtualenvwrapper, for those who like the wrapper workflow and want it alongside pyenv.

Maintenance, licence and upgrade cost

The repository is not archived, and the last push was on 2026-04-29. Release v1.4.0 carries the same date, following v1.3.0 on 2026-03-25 and v1.2.6 on 2025-12-14. That cadence suggests releases are cut when changes accumulate rather than on a fixed schedule.

Upgrading is cheap by construction. A plugin install is a Git checkout, so checking out a release tag or running `git pull` inside the plugin directory moves between versions; the README describes exactly those two operations. Homebrew users have `brew install pyenv-virtualenv` and `brew install --HEAD pyenv-virtualenv` for the development release. There is no migration step documented between versions, which is consistent with a plugin that mostly shells out to other tools.

The licence is MIT. That is permissive and imposes few obligations on redistribution, but the repository is the authority on the exact terms, and this is not legal advice. One practical note: `install.sh`, `bin/`, `libexec/` and `shims/` sit at the top level, so any packaging or vendoring work should account for the plugin layout rather than treating it as a standalone program.

Editorial conclusion

Adopt pyenv-virtualenv if you already run pyenv on a UNIX-like system and want virtualenv creation, activation and deletion to sit beside your Python version management; the README's `pyenv virtualenv-init -` hook is what makes directory-based activation work. Skip it if you are on Windows, since the README targets UNIX-like systems, or if you want a dependency and packaging manager rather than environment plumbing. Before committing, confirm that `pyenv virtualenv-init -` loads in your shell and that `pyenv virtualenvs` lists the environment you create.

Frequently asked questions

What is the difference between pyenv and virtualenv?

pyenv selects which Python interpreter a directory uses; virtualenv creates an isolated set of installed packages. pyenv-virtualenv is a pyenv plugin that manages virtualenvs and conda environments, storing them under pyenv's versions directory so pyenv can select them.

What is the purpose of pyenv?

pyenv manages which Python version is selected for a directory, using `.python-version` files that can be created with `pyenv local`. pyenv-virtualenv builds on it by adding virtualenv and conda environment management as a plugin.

How do I install pyenv-virtualenv?

The README's primary method is cloning the repository into pyenv's plugins directory with `git clone https://github.com/pyenv/pyenv-virtualenv.git $(pyenv root)/plugins/pyenv-virtualenv`. macOS users who installed pyenv with Homebrew can instead run `brew install pyenv-virtualenv`, then still add the virtualenv-init line to their shell rc file.

How do I create a virtualenv with pyenv virtualenv?

Run `pyenv virtualenv` with a Python version and a name, such as `pyenv virtualenv 2.7.10 my-virtual-env-2.7.10`, which creates the environment under `$(pyenv root)/versions`. With a single argument, the environment is created from the current pyenv Python version.

How do I activate a pyenv virtualenv?

Add `eval "$(pyenv virtualenv-init -)"` to your shell rc file and pyenv-virtualenv will activate and deactivate environments automatically when you enter or leave a directory whose `.python-version` file names a valid environment. You can also activate manually with `pyenv activate <name>` and leave with `pyenv deactivate`.

Can I install pyenv-virtualenv on Windows?

The README describes pyenv-virtualenv as providing virtualenv and conda environment management for Python on UNIX-like systems, and it documents plugin and Homebrew installation only. It does include a WSL note about setting `core.autocrlf` to `input` to avoid script execution errors, but no native Windows installation is documented.

Official sources

  1. Issues
  2. License: MIT
  3. pyenv/pyenv-virtualenv on GitHub
  4. README
  5. Releases
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pyenv-pyenv-virtualenv.svg)](https://hysenlabs.com/projects/pyenv-pyenv-virtualenv)