Python Virtual Environments Explained: venv vs conda vs pyenv
On this page
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 computing —
conda install pytorch pytorch-cuda=12.1 -c pytorch -c nvidiajust 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
- Python venv documentation — official Python docs on the venv module
- Conda documentation — official conda user guide and reference
- pyenv GitHub repository — installation instructions and usage guide
- Python Packaging User Guide — PyPA's official guide to Python packaging and virtual environments
- 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.