Python Virtual Environment Tutorial: venv, uv, poetry, pyenv
Set up isolated Python environments with venv, virtualenv, pipx, pyenv, poetry, and uv. Activation on macOS, Linux, and Windows PowerShell explained.
Python Virtual Environment Tutorial
A virtual environment is a self-contained folder that holds its own Python interpreter and its own site-packages. Every project you build should have one. Without isolation, installing a library for one project can break another, and global installs mix with the system Python that your OS depends on. This tutorial walks through the tools worth knowing in 2026 and shows the exact commands for macOS, Linux, and Windows PowerShell.
Why use a virtual environment?
- Dependency isolation. Project A can pin Django 4.2 while Project B uses Django 5.1.
- Reproducibility. A locked list of packages means teammates and CI install identical versions.
- Safety. You never run
sudo pip installagainst system Python, which can corrupt OS tooling.
The tools
venv (built in since Python 3.3)
The standard library module. Zero install, always available. This is the right default for scripts and small projects.
python -m venv .venv
virtualenv (older, third-party)
Predates venv. It is faster to create environments and supports older Python versions, but for modern work venv covers 95% of use cases. Install with pip install virtualenv, then virtualenv .venv.
pipx (for CLI tools)
When you want a command-line tool like black, httpie, or ruff available everywhere but each in its own isolated environment, use pipx. It is not for project dependencies.
pipx install ruff
pipx install httpie
pyenv (Python version manager)
pyenv installs and switches between multiple Python versions on the same machine. Combine it with venv or uv to pick the interpreter, then create the environment.
pyenv install 3.12.5
pyenv local 3.12.5
python -m venv .venv
On Windows use pyenv-win.
Poetry (project + venv + lockfile)
Poetry manages pyproject.toml, resolves dependencies, writes a poetry.lock, and creates a virtual environment for you. It is a good fit for libraries you publish to PyPI.
poetry new myproject
cd myproject
poetry add requests
poetry install
poetry run python app.py
uv (fast, Rust-based)
uv from Astral is a Rust-written package and project manager that has become the fastest-growing option. It creates environments, resolves dependencies, and locks them in one tool, and it is dramatically faster than pip. Install it with pipx install uv or the standalone installer, then:
uv venv # create .venv
uv pip install requests
uv init # start a project with pyproject.toml
uv add fastapi
uv run python app.py
Activating on each OS
Activation puts the environment's bin/Scripts folder at the front of PATH and usually prefixes your shell prompt with (.venv).
macOS and Linux (bash, zsh)
source .venv/bin/activate
deactivate
Windows PowerShell
.venv\Scripts\Activate.ps1
If PowerShell blocks the script with an execution policy error, run once:
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
Windows cmd.exe
.venv\Scripts\activate.bat
requirements.txt vs pyproject.toml
requirements.txt is a flat list of pinned packages, generated with pip freeze > requirements.txt and restored with pip install -r requirements.txt. Simple, universally understood, but has no separation between direct and transitive dependencies.
pyproject.toml (PEP 621) is the modern manifest. It declares your project metadata and direct dependencies. Tools like poetry, uv, and hatch pair it with a lockfile (poetry.lock, uv.lock) for exact reproducibility. Prefer pyproject.toml for new projects.
Common issues
- Prompt does not change. You may have opened a new terminal or activated the wrong path. Confirm with
which python(macOS/Linux) orGet-Command python(PowerShell). It should point inside.venv. - activate.bat vs Activate.ps1. These are not interchangeable. Use the one that matches your shell.
- Wrong Python version inside venv. The environment inherits from whichever interpreter created it. Use
python3.12 -m venv .venvor setpyenv localfirst. - .gitignore. Never commit the environment itself. Add these lines:
Commit.venv/ venv/ __pycache__/ *.pycrequirements.txtorpyproject.tomlplus the lockfile instead. - VS Code not detecting the venv. Open the command palette, run "Python: Select Interpreter", and pick the one inside
.venv.
A quick recommendation
Starting a new project today? Try uv init. Maintaining an existing project with a requirements.txt? Stick with python -m venv .venv and pip. Publishing a library? Poetry is still an excellent choice. All three work fine alongside pyenv when you need to juggle Python versions.