Why every project needs its own environment
The global site-packages is shared by every project: project A upgrades requests to 2.32 and project B breaks in place — that is the truth behind "it worked yesterday". A virtual environment gives each project an isolated site-packages plus its own python/pip entry points; they never interfere, and deleting the directory removes everything — the simplest form of dependency governance.
python -m venv .venv # Create it at the project root (keep the name .venv)Activate and deactivate: know the platform difference
Linux/macOS: source .venv/bin/activate; Windows PowerShell: .venv\Scripts\Activate.ps1; cmd: Scripts\activate.bat. Exit is uniformly deactivate. PowerShell complaining about script execution is its policy — Set-ExecutionPolicy -Scope CurrentUser RemoteSigned fixes it once and for all.
Point VSCode/PyCharm at the python inside .venv and the terminal auto-activates — you will rarely type these commands by hand, which is the comfortable path.
source .venv/bin/activate # Linux / macOS
.venv\Scripts\Activate.ps1 # Windows PowerShell
deactivate # Leave the virtual environmentPin dependencies: three levels of requirements.txt
(1) Loose (requests): whatever resolves, fine for prototypes; (2) Range (requests>=2.28,<3): the usual compromise; (3) Exact pin (requests==2.32.3): reproducible deploys — this is what pip freeze > requirements.txt produces. Practical advice: express intent with ranges during development, freeze a precise lockfile for release, and let the two layers do their own jobs.
The problem with committing a raw freeze as the only dependency file: cross-platform markers bring platform-specific packages (colorama on Windows, furo on Linux), breaking teammates on the other platform — split those out or add environment markers.
requests>=2.28,<3 # Range: express intent
pip freeze > requirements.txt # Lock: reproducible deploys
# Cross-platform marker example:
colorama; sys_platform == "win32"Three frequent crashes
(1) Creating the venv with the wrong interpreter: with multiple pythons installed, python -m venv may pick an old one — check python --version first, or be explicit with python3.12 -m venv .venv; (2) the environment directory was moved/renamed: venv scripts hard-code absolute paths, so deleting and recreating is the cheapest fix; (3) the IDE is not running .venv: CLI works but the IDE throws ModuleNotFoundError — the interpreter is almost certainly not pointed at the venv.
python --version # Confirm the interpreter first
python3.12 -m venv .venv # Pin the version explicitly when needed
which python # After activation it should point to the python inside .venvWhen to graduate to uv / poetry
The stdlib venv + pip covers single-project needs. Upgrade the toolchain when these signals appear: frequent dependency conflicts, a need for lockfile-based reproducible builds (pip-tools is the lightweight option), publishing to PyPI (poetry/hatch), or craving fast installs plus Python version management (uv). Master the standard tools first and let tools solve real pain — reversing the order only adds a layer of concepts to carry.
pip install pip-tools
pip-compile requirements.in # Generate a locked requirements.txtOne-page recap: the venv workflow
Create with python -m venv .venv → activate (platform-specific command) → install with pip install → range versions during development → pip freeze to lock at release → .venv goes into .gitignore, requirements.txt goes into the repo. Six steps, and environment problems stop being yours.
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
echo ".venv/" >> .gitignore