MervCodes

Tech Reviews From A Programmer

Python Virtual Environments Explained: venv vs conda vs pyenv

10 min read

If you've ever cloned a Python project, run pip install -r requirements.txt, and watched it wreck your global Python installation — welcome to the club. Or worse: two projects that need different versions of the same package, and now nothing works. This is exactly the problem virtual environments solve, but choosing between venv, conda, and pyenv isn't obvious if nobody's explained the differences.

Let me break it down based on what I've actually used in production.

TL;DR — Just Tell Me Which One

  • venv: Built into Python. Use for web dev, APIs, scripting — any pure Python project. It's the default for a reason.
  • conda: Use for data science, ML, or anything with non-Python dependencies (C extensions, CUDA). Handles both packages and Python versions.
  • pyenv: Use when you need multiple Python versions on one machine. Pair it with venv for full isolation.

The simple rule: Web dev or scripting? venv. Data science or ML? conda. Need multiple Python versions? Add pyenv.

What Is a Virtual Environment?

It's an isolated directory with its own Python binary and packages. When you activate one, your shell's PATH changes so that environment's Python takes priority over the system install. Each project gets its own dependency tree — no conflicts, no surprises.

Every major Python authority recommends virtual environments for all project work. In 2026, there's zero reason to install project dependencies globally. Don't do it.

venv — The Standard Choice

Ships with Python 3.3+, requires nothing extra. For roughly 80% of Python projects — web apps, APIs, CLI tools, automation — this is all you need.

Setup

# Create
python3 -m venv .venv

# Activate (macOS/Linux)
source .venv/bin/activate

# Activate (Windows)
.venv\Scripts\activate

# Your prompt changes
(.venv) $ python --version
Python 3.12.4

# Install packages — they go into .venv, not your system
pip install flask requests

# Freeze dependencies
pip freeze > requirements.txt

# Deactivate
deactivate

Best Practices

Name it .venv with the dot. VS Code, PyCharm, and most tools auto-detect this. Add it to .gitignore — never commit the environment.

# .gitignore
.venv/
__pycache__/
*.pyc

Use pip-tools for deterministic builds. Plain pip freeze is fragile. pip-tools separates what you want from what you get:

pip install pip-tools

# Top-level deps
echo "flask>=3.0" > requirements.in
echo "requests>=2.31" >> requirements.in

# Compile pinned file with all transitive deps
pip-compile requirements.in

# Install exactly what's pinned
pip-sync requirements.txt

Where venv Falls Short

It can't install a different Python version. If you need 3.11 but your system has 3.12, venv can't help — it creates environments from whatever python3 is on your PATH. It also can't manage non-Python deps like libffi, openssl, or CUDA. For those, you need pyenv or conda.

conda — The Data Science Tool

Conda manages Python packages, Python versions, AND non-Python dependencies in a single tool. It's dominant in data science and ML for good reason.

Miniconda vs Anaconda

Use Miniconda. Anaconda ships 250+ pre-installed packages (~3GB), most of which you won't need. Miniconda is just conda + Python + essentials, about 80MB.

# Install Miniconda
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh
bash Miniconda3-latest-Linux-x86_64.sh

# Create environment with specific Python version
conda create -n myproject python=3.11

# Activate
conda activate myproject

# Install — conda resolves non-Python deps automatically
conda install numpy pandas scikit-learn

# PyPI-only packages
pip install some-pypi-only-package

# Export
conda env export > environment.yml

# Recreate elsewhere
conda env create -f environment.yml

Use conda-forge

The default Anaconda channel has licensing restrictions for commercial use (200+ employee orgs need a paid license). Set conda-forge as default — it's community-maintained and fully open source:

conda config --add channels conda-forge
conda config --set channel_priority strict

When to Pick conda

  • NumPy, SciPy, or packages with C/Fortran extensions — conda ships pre-compiled, optimized binaries. No more "building wheel" nightmares.
  • CUDA and GPU computingconda install pytorch pytorch-cuda=12.1 -c pytorch -c nvidia just works. Try doing that with pip.
  • Cross-language deps — need R alongside Python? Conda handles it.
  • Reproducible ML pipelines — environment.yml captures the full stack.

Downsides

Dependency resolution is slower than pip's (though libmamba made it dramatically better). Environments are bigger on disk — a basic conda env with NumPy is ~400MB vs ~50MB with venv+pip.

pyenv — Python Version Manager

pyenv doesn't create environments — it manages multiple Python installations. Think nvm for Python. Install any version, switch per-project or globally.

Setup

# macOS
brew install pyenv

# Linux
curl https://pyenv.run | bash

# Add to shell config
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init -)"

# Install versions
pyenv install 3.12.4
pyenv install 3.11.9

# Set global default
pyenv global 3.12.4

# Set project-specific
cd ~/projects/legacy-app
pyenv local 3.11.9
# Creates .python-version file

Pairing pyenv with venv

This is my go-to setup for web projects:

cd ~/projects/my-api
pyenv local 3.12.4

python -m venv .venv
source .venv/bin/activate

python --version  # Python 3.12.4
which python      # ~/projects/my-api/.venv/bin/python

Or use pyenv-virtualenv for tighter integration:

brew install pyenv-virtualenv
pyenv virtualenv 3.12.4 my-api-env
pyenv local my-api-env
# Auto-activates when entering directory

Windows

pyenv doesn't officially support Windows. Use pyenv-win:

Invoke-WebRequest -UseBasicParsing -Uri "https://raw.githubusercontent.com/pyenv-win/pyenv-win/master/pyenv-win/install-pyenv-win.ps1" -OutFile "./install-pyenv-win.ps1"; &"./install-pyenv-win.ps1"

If you're on Windows doing data science, conda is the path of least resistance.

Comparison

Feature venv conda pyenv
Manages Python versions No Yes Yes
Manages packages Via pip Yes (own solver) No
Non-Python dependencies No Yes No
Built into Python Yes (3.3+) No No
Disk usage (base env) ~20 MB ~400 MB ~50 MB per version
Environment creation speed < 1 second 5-30 seconds N/A (version install: minutes)
Best for Web dev, scripting Data science, ML Multi-version management
Windows support Native Native Via pyenv-win (unofficial)

Common Mistakes

Mixing pip and conda. If you're using conda, install everything with conda install first, then pip install only for conda-unavailable packages. Never run conda install after pip install — it can silently overwrite pip-installed packages.

Forgetting to activate. You run pip install and it goes to system Python. Set your shell to show the active env in the prompt, and use editor extensions that auto-activate.

Not pinning Python in CI. Your app works with 3.12.4 locally, CI runs 3.12.1, something breaks. Always specify the exact version:

- uses: actions/setup-python@v5
  with:
    python-version-file: '.python-version'

Committing your venv. The .venv directory has platform-specific binaries. Commit requirements.txt or environment.yml — never the environment itself.

What About Docker?

Docker sidesteps virtual environments entirely — your Dockerfile specifies the exact Python version and installs deps in an isolated container. For production, this is often the cleanest approach.

That said, most developers still use virtual environments locally even alongside Docker. The feedback loop is faster and IDE integration works better with a local .venv.

My Recommended Setup

Web developers:

  • pyenv for version management
  • venv for per-project isolation
  • pip-tools for dependency pinning
  • Docker for production

Data scientists:

  • Miniconda with conda-forge
  • environment.yml in version control
  • Separate environments per project, always

Solo / scripting:

  • Just venv. Don't overthink it.

Worth watching: uv from Astral (the Ruff team) is a Rust-based pip replacement that's 10-100x faster. It can manage Python versions too. Not yet standard, but gaining traction fast.

Sources

  1. Python venv documentation — official Python docs on the venv module
  2. Conda documentation — official conda user guide and reference
  3. pyenv GitHub repository — installation instructions and usage guide
  4. Python Packaging User Guide — PyPA's official guide to Python packaging and virtual environments
  5. uv: An extremely fast Python package installer — Astral's Rust-based pip replacement

Related Articles

How to Debug Node.js Memory Leaks (Step-by-Step Guide)

Learn how to detect, diagnose, and fix Node.js memory leaks using heap snapshots, Chrome DevTools, and clinic.js — with real code examples.

How to Set Up GitHub Actions for CI/CD (Beginner-Friendly Guide)

Learn how to set up GitHub Actions for CI/CD pipelines — from your first workflow file to automated deployments with real YAML examples.

Running Local LLMs With Ollama: Developer Setup Guide

Set up Ollama to run local LLMs on your machine. Covers installation, model selection, API usage, and integrating local models into your dev workflow.