Virtual Environments with venv
If you've installed Python packages with pip install straight into your system Python, you've probably hit (or will soon hit) one of these problems: two projects need different versions of the same library, an upgrade for one project breaks another, or your operating system refuses to let you install anything at all. Virtual environments solve all of these, and venv is the tool that ships with Python to create them.
What is a Virtual Environment?
A virtual environment is a self-contained directory that holds:
- A link to a Python interpreter: The version you created it with
- Its own
site-packagesfolder: Where installed packages live - Its own copy of pip: Installs go into this environment only
- Activation scripts: Put the environment's
pythonandpipfirst on your PATH
Each project gets its own environment, so packages installed for one project never touch another project or your system Python.
Real-world analogy: A virtual environment is like giving each project its own toolbox. You don't have to worry that someone swapped the wrench in your toolbox for a different size while working on their project.
Why It Matters Today
1. Your OS Won't Let You Install Globally Anymore
Modern Linux distributions (Debian 12+, Ubuntu 23.04+, Fedora and others) and Homebrew Python on macOS mark the system Python as externally managed (PEP 668). Try to pip install into it and you'll see:
$ pip install requests
error: externally-managed-environment
ร This environment is externally managed
โฐโ> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
The system Python belongs to your operating system, and tools you rely on depend on the exact package versions it ships. The fix isn't --break-system-packages - it's a virtual environment.
2. Projects Have Conflicting Dependencies
project_a/ needs pandas 1.5 (old code, not yet migrated)
project_b/ needs pandas 2.2 (new code using new features)
Without isolation, only one version can be installed at a time. With a virtual environment per project, both work side by side.
3. Reproducibility
When your dependencies live in an isolated environment, pip freeze lists exactly what your project needs - not every package you've ever installed. That makes it possible for a teammate, a CI server, or a Docker build to recreate your setup exactly.
4. Safe Experimentation
Want to try a new library or a pre-release version? Create a throwaway environment, experiment, and delete the folder when you're done. Nothing else on your machine is affected.
5. Supply-Chain Hygiene
Installing packages runs code from the internet. Keeping each project's packages in its own environment limits what a bad or compromised package can reach, and makes it easy to audit what a project actually depends on.
Using venv
venv has been part of Python's standard library since Python 3.3 - there's nothing extra to install.
Note for Debian/Ubuntu: the
venvmodule is split into a separate package. If you get an error aboutensurepip, runsudo apt install python3-venv.
Creating an Environment
# Navigate to your project
cd my_project
# Create a virtual environment in a folder named .venv
python -m venv .venv
# On some systems
python3 -m venv .venv
Naming it .venv is the common convention - VS Code, PyCharm, and most other tools detect it automatically.
Activating the Environment
# macOS/Linux (bash/zsh)
source .venv/bin/activate
# Windows (Command Prompt)
.venv\Scripts\activate.bat
# Windows (PowerShell)
.venv\Scripts\Activate.ps1
Once activated, your prompt shows the environment name:
(.venv) $ which python
/home/you/my_project/.venv/bin/python
PowerShell tip: if activation is blocked, run
Set-ExecutionPolicy -Scope CurrentUser RemoteSignedonce.
Installing Packages
With the environment active, pip installs into the environment only:
(.venv) $ pip install requests pandas
(.venv) $ pip list
Saving and Restoring Dependencies
# Save the exact versions you're using
pip freeze > requirements.txt
# Recreate the environment somewhere else
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
Deactivating
(.venv) $ deactivate
$
Running Without Activating
Activation is just a convenience. You can call the environment's Python directly, which is handy in scripts, cron jobs, and systemd services:
.venv/bin/python main.py
.venv/bin/pip install requests
Deleting an Environment
A virtual environment is just a folder. If it gets messed up, delete it and recreate it:
rm -rf .venv
python -m venv .venv
pip install -r requirements.txt
Best Practices
1. Never Commit the Environment
Add it to your .gitignore:
.venv/
Commit requirements.txt (or pyproject.toml) instead - that's the recipe, the environment is the cooked meal.
2. One Environment Per Project
Keep the .venv folder inside the project it belongs to. It's easy to find, easy for editors to detect, and easy to delete.
3. Don't Move or Rename It
Environments contain absolute paths. If you move the project folder, recreate the environment rather than trying to fix it.
4. Upgrade pip Inside New Environments
python -m pip install --upgrade pip
5. Point Your Editor at It
In VS Code: Ctrl+Shift+P โ "Python: Select Interpreter" โ choose the .venv interpreter. See the Development Environment guide for more editor setup.
Quick Reference
| Task | Command (macOS/Linux) | Command (Windows) |
|---|---|---|
| Create | python3 -m venv .venv | python -m venv .venv |
| Activate | source .venv/bin/activate | .venv\Scripts\activate |
| Install package | pip install name | pip install name |
| Save deps | pip freeze > requirements.txt | pip freeze > requirements.txt |
| Restore deps | pip install -r requirements.txt | pip install -r requirements.txt |
| Deactivate | deactivate | deactivate |
| Remove | rm -rf .venv | rmdir /s .venv |
Modern Alternatives
venv + pip is the built-in foundation, and it's worth understanding because every other tool builds on the same idea. But it leaves a few jobs to you: installing different Python versions, locking exact dependency versions (including sub-dependencies), and keeping requirements.txt in sync. Newer tools handle those for you.
uv
An extremely fast all-in-one tool written in Rust by Astral (the makers of Ruff). It replaces venv, pip, pip-tools, pyenv, and pipx in one binary.
uv init my_project # create a project with pyproject.toml
uv add requests # add a dependency (creates .venv automatically)
uv run main.py # run inside the environment - no activation needed
uv python install 3.13 # install a Python version
How it differs: 10-100x faster than pip, manages Python versions itself, writes a cross-platform uv.lock lockfile, and creates/syncs the .venv for you. It also has a pip-compatible mode (uv venv, uv pip install) if you want to keep your existing workflow and just make it faster. This is the current go-to recommendation for new projects.
Poetry
A mature dependency manager and packaging tool.
poetry new my_project
poetry add requests
poetry run python main.py
How it differs: Manages dependencies in pyproject.toml with a poetry.lock lockfile and a strong dependency resolver, and builds/publishes packages to PyPI. It creates virtual environments for you but doesn't install Python versions. Slower than uv, but widely used and well documented.
Pipenv
One of the first tools to combine pip and virtualenv.
How it differs: Uses a Pipfile and Pipfile.lock instead of requirements.txt. Still maintained and found in plenty of existing projects, but most new projects choose uv or Poetry instead.
Conda / Mamba / Pixi
Environment managers from the scientific Python world.
How it differs: Can install non-Python dependencies (C libraries, CUDA, compilers, R) alongside Python packages, which is why they're popular in data science and machine learning. Environments typically live in a central location rather than in your project folder. Mamba is a faster drop-in for conda; Pixi is a newer, project-based tool built on the conda ecosystem.
pyenv
How it differs: Not a venv replacement - it installs and switches between multiple Python versions. Traditionally paired with venv (pyenv picks the Python, venv isolates the packages). uv now covers both jobs.
Comparison
| Tool | Creates envs | Installs Python versions | Lockfile | Non-Python deps | Speed |
|---|---|---|---|---|---|
| venv + pip | โ | โ | โ | โ | Baseline |
| uv | โ | โ | โ | โ | Very fast |
| Poetry | โ | โ | โ | โ | Moderate |
| Pipenv | โ | โ | โ | โ | Slow |
| Conda / Pixi | โ | โ | Pixi โ | โ | Moderate / fast |
Which should you use?
- Learning Python or writing a quick script?
venv- it's always there and teaches you how environments actually work. - Starting a new project?
uv- fast, simple, and handles everything. - Joining an existing project? Use whatever it already uses (look for
uv.lock,poetry.lock,Pipfile, orenvironment.yml). - Heavy data science / GPU work with native libraries? Conda or Pixi.
What's Next?
- Set up your development environment
- Write your first Python program
- Get started with Pandas - in its own virtual environment!
Resources
- Python docs - venv: docs.python.org/3/library/venv.html
- Python Packaging User Guide: packaging.python.org
- PEP 668 - Externally Managed Environments: peps.python.org/pep-0668
- uv documentation: docs.astral.sh/uv
Make creating a virtual environment the first thing you do in every new Python project. It takes five seconds and saves hours of dependency headaches later.

