Skip to content

pyenv

venv/conda/uv solve the problem of “how to isolate dependencies under a single Python version.” pyenv solves a more fundamental problem: how to install and switch between multiple Python interpreter versions on the same machine. Different projects may require different major Python versions (an older project still on 3.8, a new one requiring 3.12), and the system’s bundled Python usually isn’t safe to upgrade or downgrade directly. pyenv installs Python by compiling from source into a per-user directory, letting multiple versions coexist and switch automatically per directory.

Installing Build Dependencies

pyenv installs Python interpreters by compiling from source, so you need the build toolchain in place first (CentOS/RHEL example):

yum install -y git curl
yum install -y gcc make patch gdbm-devel openssl-devel
yum install -y sqlite-devel readline-devel zlib-devel bzip2-devel

Installing pyenv

# Official automatic installer
curl -L https://github.com/pyenv/pyenv-installer/raw/master/bin/pyenv-installer | bash

# If GitHub is slow to reach, download the script and run it locally instead
# https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer

# Update pyenv itself later on
pyenv update

After installation, append the following to the end of ~/.bashrc (or ~/.zshrc) as instructed, then re-login or source it to take effect:

export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
If your server has slow access to download Python source tarballs, you can pre-download the source package for the version you want and place it in ~/.pyenv/cache/ (create the directory if it doesn’t exist) — pyenv will use the local cache first during installation.

Installing and Switching Python Versions

# List all installable versions
pyenv install -l

# Install a specific version (compiled from source — the first time is slow)
pyenv install 3.12.7

# Show the currently active version; "system" means pyenv isn't managing it and the OS-bundled Python is in use
pyenv version

# List all installed versions; the * marks the one currently in use
pyenv versions

# Switch the global default version
pyenv global 3.12.7

Pinning a Version per Directory

pyenv local generates a .python-version file in the current directory; entering that directory (or any subdirectory) automatically switches to the pinned version — very handy when working on multiple projects in parallel:

mkdir -p projects/demo
cd projects/demo

pyenv local 3.12.7
python -V   # Python 3.12.7

Creating Virtual Environments with pyenv-virtualenv

pyenv-installer also installs the pyenv-virtualenv plugin, which lets you create a virtual environment directly on top of a given pyenv version — effectively combining version management and dependency isolation into one step:

# Create a virtual environment named myproject on top of the 3.12.7 interpreter
pyenv virtualenv 3.12.7 myproject

# Make the current directory use this virtual environment automatically (generates .python-version)
pyenv local myproject

# Verify
python -V
pyenv version
# myproject (set by /home/user/projects/demo/.python-version)

Summary

pyenv’s strength is letting multiple Python versions coexist and switch automatically, which suits machines that need to maintain several legacy projects side by side, or scenarios requiring precise control over the interpreter version (especially Linux servers). Its downside is that installation relies on compiling from source, which is slow, and it doesn’t manage a project’s third-party package dependencies. In everyday use, uv already has equivalent built-in Python version management (uv python install/pin) — if your project can adopt a new tool, going straight to uv covers both needs at once. Only reach for pyenv specifically when you already depend on its ecosystem, such as an existing pyenv-virtualenv workflow.

Last updated on