Python Virtual Environments Guide
Stop polluting your system Python — a practical guide to virtual environments with venv, activating and deactivating them, requirements.txt, and a quick look at modern alternatives.
What you'll learn
- ✓Why virtual environments exist
- ✓Creating and activating a venv
- ✓Installing packages and freezing requirements
- ✓Recreating an environment from requirements.txt
- ✓Modern alternatives like uv, poetry, and pipx
Prerequisites
- •Basic Python familiarity
A virtual environment is an isolated Python installation that lives inside a folder in your project. It has its own copy of python, its own pip, and its own site-packages directory. The point is simple: each project gets its own dependencies, and nothing you install for one project leaks into another or into your system Python.
Why You Need One
Without a virtual environment, every pip install modifies the same shared site-packages. That leads to predictable trouble:
- Project A needs
requests==2.20, project B needsrequests==2.31. Only one can win. - Upgrading a library to fix one project quietly breaks another.
- Your system package manager installs Python tools too, and
pip installcan collide with them. - Reproducing a colleague’s setup becomes archaeology.
A virtual environment per project sidesteps all of this. Treat it as a hard rule: every project gets its own venv.
Creating a venv
Python ships a built-in module called venv.
python3 -m venv .venv
This creates a .venv directory in the current folder. The leading dot is convention — it hides the folder in most file browsers and signals “tooling, not source code.” The folder contains a Python binary, a copy of pip, and an empty site-packages.
You can pick any name you like, but .venv is the de facto standard and is recognised by most editors automatically.
Activating It
Activating a venv adjusts your shell’s PATH so that python and pip point at the venv’s copies.
On macOS or Linux:
source .venv/bin/activate
On Windows (PowerShell):
.venv\Scripts\Activate.ps1
You will see your prompt change to include (.venv) as a reminder. From now on, pip install puts packages into .venv/lib/.../site-packages and nowhere else.
To leave the venv:
deactivate
Installing Packages
Once activated, install packages exactly as you would normally.
pip install requests
pip install "flask>=3.0"
You can confirm what is installed with pip list or pip show requests. Everything you install affects only this project.
Pinning Dependencies with requirements.txt
To make your environment reproducible — for a teammate, a CI server, or a future you — record the installed versions.
pip freeze > requirements.txt
This writes every installed package with its exact version. Commit the file. To recreate the environment elsewhere:
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
That is the entire onboarding ritual for a Python project.
A common refinement is to keep two files: requirements.txt for the direct dependencies you actually want, and requirements.lock.txt for the full pinned set generated from pip freeze. That way upgrades are clear and intentional.
A Tiny Example Project
# app.py
import requests
r = requests.get("https://example.com")
print(r.status_code)
Setup, run, and tear down:
python3 -m venv .venv
source .venv/bin/activate
pip install requests
python app.py
deactivate
That is the whole workflow. The exact same sequence works for every Python project you will ever start.
Editor Integration
Most editors detect a .venv folder automatically and use its interpreter for linting, autocomplete, and type checking. In VS Code, the Python extension shows the active interpreter in the status bar — click it to switch between venvs. In PyCharm, the interpreter is set per project under Settings -> Python Interpreter.
If your editor is using the wrong Python — and you cannot understand why type hints don’t resolve — check that it is pointed at the venv.
Common Mistakes
Installing without activating. Running pip install in a shell where the venv is not active dumps packages into your system Python again. The fix is to always check for (.venv) in your prompt before running pip.
Committing the venv folder. Add .venv/ to .gitignore. Virtual environments are not portable across machines or even Python versions, and they are large. Commit requirements.txt instead and let collaborators rebuild.
Forgetting to upgrade pip. After creating a venv, pip install --upgrade pip is a sensible first step. The pip bundled with venv is often a few releases behind.
Modern Alternatives
The Python packaging world has moved fast. A few tools worth knowing about:
- uv is a recent Rust-based tool that creates venvs and installs packages dramatically faster than pip. Drop-in compatible for most workflows.
- poetry manages dependencies, virtual environments, and packaging from a single
pyproject.toml. Popular in libraries and serious applications. - pipx installs Python applications (not libraries) into their own venvs and exposes their CLIs globally. Great for tools like
httpie,ruff, ormypy. - conda ships its own environments and is dominant in scientific Python, where binary packages with native dependencies matter.
You don’t need any of these to get started. The built-in venv plus pip handles every project well enough until you have a reason to switch.
A Quick Mental Model
Every Python project should answer two questions on day one: where does its Python live, and where do its packages live. A venv answers both — the binary in .venv/bin/python and the packages in .venv/lib/.../site-packages. Once you have internalised that, nothing about Python environments feels mysterious anymore.
Wrapping Up
Virtual environments take less than thirty seconds to set up and prevent a long list of headaches. Make python3 -m venv .venv the first command you run in every new project, commit a requirements.txt, and your future self will be glad you did.
Related articles
- Python Python Packages, pip, and pyproject.toml
Install, pin, and publish — a practical tour of pip, PEP 621 pyproject.toml, and building a tiny library you can share on TestPyPI.
- Python Python asyncio Event Loop Guide
Understand how Python's asyncio event loop schedules coroutines, what await actually does, and how to avoid the classic mistakes that turn async code into a tangle of bugs.
- Python Python Decorators Deep Dive
A practical tour of Python decorators: how they work under the hood, when to use them, and how to write decorators that preserve metadata, accept arguments, and stack cleanly.
- Python Python Logging Best Practices
How to set up Python logging properly: loggers vs handlers, structured logs, contextual fields, log levels that scale, and how to avoid the classic print-debug trap.