env.dev

Python Virtual Environments: venv, uv, Poetry & pyenv

Manage Python environments with venv, pip, pyenv, Poetry, and conda. Learn requirements.txt, pyproject.toml, and environment best practices.

Last updated:

A Python virtual environment is an isolated directory tree that contains its own Python interpreter and packages, independent of the system-wide installation. Virtual environments prevent version conflicts between projects — for example, Project A needing Django 4.2 while Project B requires Django 5.0. The Python Packaging Authority (PyPA) recommends always using virtual environments. As of Python 3.12, venv is the built-in standard, but tools like Poetry, uv, pyenv, and conda offer additional capabilities for dependency resolution, Python version management, and reproducible builds. For configuring secrets and runtime settings inside an activated environment, see Python environment variables.

How Does venv Work?

The venv module ships with Python 3.3+ and creates a lightweight virtual environment by symlinking (or copying) the Python binary and creating an isolated site-packages directory. When activated, the shell's PATH is modified so that python and pip point to the environment's copies.

Create and activate a venv
# Create a virtual environment
python3 -m venv .venv

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

# Activate (Windows PowerShell)
.venv\Scripts\Activate.ps1

# Verify isolation
which python    # → .venv/bin/python
pip list        # → only pip and setuptools

# Deactivate
deactivate

Tip: Always add .venv/ to your .gitignore. The environment itself should never be committed — only the dependency specification file.

How Do You Manage Dependencies with pip?

pip is the standard package installer for Python. Use requirements.txt to pin exact versions for reproducible installs.

pip workflow
# Install packages
pip install requests==2.31.0 flask==3.0.0

# Freeze all installed packages (exact versions)
pip freeze > requirements.txt

# Install from requirements file
pip install -r requirements.txt

# Upgrade a package
pip install --upgrade requests

# Uninstall
pip uninstall requests
requirements.txt
# Pin exact versions for reproducibility
requests==2.31.0
flask==3.0.0
gunicorn==21.2.0
psycopg2-binary==2.9.9

# Separate dev dependencies in requirements-dev.txt
-r requirements.txt
pytest==7.4.3
black==23.12.1
mypy==1.8.0

What Is pyenv and When Should You Use It?

pyenv manages multiple Python versions on a single machine. It intercepts Python commands via shims in your PATH and routes them to the correct version. Use pyenv when different projects need different Python versions (e.g., 3.10 vs 3.12).

pyenv usage
# Install a Python version
pyenv install 3.12.1

# Set global default
pyenv global 3.12.1

# Set per-project version (creates .python-version file)
cd my-project
pyenv local 3.11.7

# List installed versions
pyenv versions

# Combine with venv
pyenv local 3.12.1
python -m venv .venv
source .venv/bin/activate

How Does Poetry Handle Virtual Environments?

Poetry is an all-in-one dependency manager that handles virtual environment creation, dependency resolution, and packaging. It uses pyproject.toml for configuration and generates a poetry.lock file for deterministic installs. Poetry automatically creates and manages virtual environments per project.

Poetry workflow
# Create a new project
poetry new my-project

# Or initialize in an existing directory
poetry init

# Add dependencies
poetry add requests flask
poetry add --group dev pytest black mypy

# Install all dependencies (creates venv automatically)
poetry install

# Run commands inside the virtual environment
poetry run python main.py
poetry run pytest

# Activate the shell
poetry shell

# Export to requirements.txt (for Docker/CI)
poetry export -f requirements.txt --output requirements.txt
pyproject.toml (Poetry)
[tool.poetry]
name = "my-project"
version = "1.0.0"
description = "Example project"

[tool.poetry.dependencies]
python = "^3.11"
requests = "^2.31.0"
flask = "^3.0.0"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.3"
black = "^23.12.1"
mypy = "^1.8.0"

[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

How Does uv Compare to Poetry?

uv is a Rust-based, drop-in replacement for pip, pip-tools, virtualenv, pipx, and Poetry from Astral (the team behind Ruff). It reads the same pyproject.toml as Poetry, manages Python versions itself (no pyenv needed), and ships a uv.lock for deterministic installs. Astral's published benchmarks show uv resolving and installing dependencies 10–100× faster than pip, which is why it has become the default recommendation for new Python projects in 2025–2026.

uv workflow
# Install uv (one-time)
curl -LsSf https://astral.sh/uv/install.sh | sh

# Create a virtual environment (defaults to .venv)
uv venv

# Install Python itself if missing
uv python install 3.12

# Add dependencies to pyproject.toml + uv.lock
uv add requests flask
uv add --dev pytest mypy

# Install everything from pyproject.toml / uv.lock
uv sync

# pip-compatible interface (no activation required)
uv pip install requests
uv pip install -r requirements.txt

# Run a command inside the environment
uv run python main.py
uv run pytest

When Should You Use conda?

conda is a cross-platform package and environment manager that handles both Python and non-Python dependencies (C libraries, CUDA, R, etc.). It is the standard in data science and machine learning because packages like NumPy and TensorFlow often depend on compiled C/Fortran libraries that pip cannot manage. Use conda when your project has non-Python binary dependencies.

conda workflow
# Create an environment with a specific Python version
conda create -n myenv python=3.12

# Activate
conda activate myenv

# Install packages
conda install numpy pandas scikit-learn

# Export environment
conda env export > environment.yml

# Recreate from file
conda env create -f environment.yml

# List environments
conda env list

# Remove an environment
conda env remove -n myenv

How Do These Tools Compare?

Featurevenv + pipPoetryuvcondapyenv
Python version managementNoNoYesYesYes
Dependency resolutionBasicAdvanced (SAT solver)Advanced (Rust resolver)AdvancedN/A
Lock fileManual (pip freeze)poetry.lockuv.lockenvironment.ymlN/A
Non-Python depsNoNoNoYesNo
Built into PythonYesNoNoNoNo
Best forSimple projectsApps & librariesModern apps & monoreposData scienceMulti-version Python

Common pitfalls

  • Committing the .venv/ directory. Virtual environments are machine-specific and bloat the repo. Add .venv/ to .gitignore and commit only the dependency manifest (pyproject.toml, requirements.txt, plus the lock file).
  • Mixing pip install with Poetry or uv. Running pip install inside a Poetry/uv-managed environment skips the resolver and lock file, so the next poetry install / uv sync wipes your changes. Always go through the project tool (poetry add, uv add).
  • Forgetting to activate. A fresh shell starts with the system Python on PATH. Check which python before installing — or use poetry run / uv run to bypass activation entirely.
  • Installing into the system Python on macOS. The Apple-bundled Python is read-only and reserved for the OS. Use Homebrew, pyenv, or uv python install to get a writable interpreter, then create a venv from there.

References

Which Python Environment Tool Should You Pick?

  • • Always use a virtual environment — never install packages into the system Python
  • venv + pip is the zero-dependency default; use it for simple projects and scripts
  • Poetry adds proper dependency resolution and lock files — ideal for applications and libraries
  • uv is the fastest modern option (10–100× faster than pip) and replaces venv + pip + Poetry + pyenv in one binary — preferred for new apps and monorepos
  • conda is necessary when your stack includes compiled C/Fortran/CUDA dependencies
  • pyenv complements any tool above when you need multiple Python versions on one machine
  • • Pin exact versions in production; use compatible-release specifiers (~=) or caret (^) in libraries
  • • Keep the syntax handy with the Python cheatsheet for quick reference inside any environment.
Was this helpful?

Read next

How to Build an MCP Server: TypeScript & Python (2026)

Build a Model Context Protocol server in TypeScript or Python in 2026: SDK quickstart, transports (stdio vs Streamable HTTP), security, and client setup.

Continue →

Frequently Asked Questions

What is a Python virtual environment?

A virtual environment is an isolated Python installation with its own packages. It prevents dependency conflicts between projects. Create one with python -m venv .venv and activate it before installing packages.

Should I use pip or Poetry?

Use pip for simple projects with requirements.txt. Use Poetry for projects that need dependency resolution, lockfiles, and pyproject.toml management. Poetry is the modern choice for new Python projects.

What is pyenv?

pyenv manages multiple Python versions on your system. Install different Python versions and switch between them per-project using .python-version files. Works well alongside virtual environments.

Should I switch from Poetry to uv in 2026?

Probably yes for new projects. uv (from Astral, the makers of Ruff) is a Rust-based drop-in replacement for pip, pip-tools, virtualenv, pipx, and Poetry that resolves and installs dependencies 10–100× faster than pip per Astral's published benchmarks. It reads the same pyproject.toml as Poetry, generates a uv.lock, and manages Python versions itself — so you can drop Poetry and pyenv at the same time. For existing Poetry projects with stable workflows the switch is optional, but greenfield apps and monorepos benefit most.

Stay up to date

Get notified about new guides, tools, and cheatsheets.