Virtual environments explained for humans

Why every Python project needs its own sandbox, what venv/poetry/uv actually do, and how to stop your projects from breaking each other.

Virtual environments explained for humans

You installed a package for one project and now a completely different project crashes. Sound familiar? Congratulations, you’ve just discovered why virtual environments exist.

The problem in 30 seconds

Python has one global site-packages folder where pip install dumps everything. If Project A needs pandas 1.5 and Project B needs pandas 2.1, you have a fight. The last one installed wins, and the other project breaks. Silently, of course — Python is polite like that.

A virtual environment gives each project its own isolated site-packages folder. Project A gets its pandas 1.5, Project B gets its pandas 2.1, and they never know about each other. Problem solved.

The built-in way: venv

Python ships with venv since version 3.3. No installation needed.

# Create a virtual environment in a folder called .venv
python -m venv .venv

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

# Activate it (Windows)
.venv\Scripts\activate

# Now pip install goes into .venv, not your system Python
pip install pandas==2.1.0

When you’re done, deactivate to go back to your system Python. The .venv folder is just a regular directory — delete it and the environment is gone.

Things people forget

  • Add .venv/ to .gitignore. You don’t commit the environment. You commit a requirements.txt (or pyproject.toml) and recreate it wherever you deploy.
  • Always freeze your dependencies. pip freeze > requirements.txt saves the exact versions you have installed. Without this, pip install grabs the latest version and things might break in production.
  • One environment per project. Don’t share environments between projects unless you want to relive the exact problem you were trying to solve.

Poetry: the grown-up option

venv + pip + requirements.txt works but has sharp edges. Poetry wraps the whole workflow into one tool:

# Install poetry (once)
pip install poetry

# Start a new project
poetry init

# Add a dependency
poetry add pandas

# Install from the lock file (exact versions, reproducible)
poetry install

Poetry generates a pyproject.toml (your requirements) and a poetry.lock (pinned versions of every dependency, including sub-dependencies). The lock file is the thing that makes builds reproducible — commit it.

Poetry creates and manages the virtual environment for you automatically. You never need to activate it manually; poetry run python script.py runs inside the environment.

When to use it

  • Projects with more than a handful of dependencies
  • Anything that ships to production or gets shared with a team
  • When you’re tired of manually syncing requirements.txt

uv: the new fast kid

uv is a relatively new tool (by the Astral team, the same people behind ruff) that replaces pip, pip-tools, virtualenv, and parts of Poetry in a single Rust binary. It’s fast — 10–100× faster than pip for resolution and installation.

# Install uv
pip install uv

# Create a venv
uv venv

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

# Or manage a project (poetry-like workflow)
uv init
uv add pandas
uv sync

uv is still maturing, but it’s already excellent for:

  • Fast dependency installation in CI pipelines
  • Projects where you want one tool to handle environments + packages
  • Anyone who’s tired of waiting 30 seconds for pip to resolve a dependency tree

Which one should you use?

You need…Use
Something that just works, no installvenv + pip
Reproducible builds + dependency managementPoetry
Speed above all, bleeding edge OKuv
A data science notebook, path of least resistanceconda

If you’re just starting out, venv + pip is fine. Learn how environments work at the fundamental level before adding abstractions on top. Once you feel the pain of manually managing requirements.txt across multiple projects, Poetry is the natural next step.

The important thing isn’t which tool. It’s that you use one of them. Running pip install into your global Python is how you end up reinstalling everything from scratch every six months.

The one-sentence rule

Every Python project gets its own virtual environment, always, no exceptions, even if it’s a tiny script. The three minutes it takes to set up saves three hours of debugging dependency conflicts later.