Python Virtual Environments Explained in the Easiest Possible Way

Posted November 17, 2025 by Karol Polakowski

Virtual environments are lightweight, isolated Python environments that keep your project dependencies separate from your system Python and from other projects. They make your projects reproducible, prevent package version conflicts, and keep your development environment clean.

What is a Python virtual environment?

A virtual environment (venv) is a directory that contains a specific Python interpreter and a local copy of the site-packages directory. When you activate a venv, commands like python and pip point to the interpreter and package installer inside that directory instead of the system-wide ones.

Why this matters:

  • Different projects can require different versions of the same package (for example, Django 2.x vs 4.x). venvs avoid conflicts.
  • You can test against multiple Python versions without polluting the global environment.
  • Deploying becomes easier when you freeze dependencies and recreate the same environment.

Quick terminology

  • venv: Built-in module in Python 3 (recommended and simple).
  • virtualenv: Popular third-party tool compatible with older Python versions — sometimes faster and with extra features.
  • pipx: Installs and runs Python CLI tools in isolated environments, good for global CLIs.
  • Poetry / Pipenv: Higher-level tools that manage venvs, dependency resolution, and packaging.

Create a virtual environment (venv)

Create a venv in your project folder and activate it (recommended name: .venv or venv):

# Create the venv
python -m venv .venv

# Activate on macOS / Linux (bash/zsh)
source .venv/bin/activate

# Activate on Windows (PowerShell)
.\.venv\Scripts\Activate.ps1

# Deactivate
deactivate

Notes:

  • Using a dot-prefixed directory like .venv keeps it hidden in many file explorers.
  • You can use any directory name; just be consistent and add it to .gitignore.

Installing packages and freezing requirements

Inside an activated venv:

# Install packages
pip install requests flask

# Show installed packages
pip list

# Freeze to requirements.txt for reproducible installs
pip freeze > requirements.txt

# Recreate environment on another machine
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Using virtualenv (older or specific needs)

virtualenv gives a similar workflow and works with older Pythons:

pip install virtualenv
virtualenv venv-env
source venv-env/bin/activate

pipx — install CLI tools globally but isolated

Use pipx to install command-line tools without polluting your main environment:

pip install --user pipx
python -m pipx ensurepath
pipx install black
# Run black anywhere
black my_file.py

pipx installs each tool into its own isolated environment and places shims on your PATH.

Poetry — dependency management + venv management

Poetry automates dependency resolution and creates project venvs (recommended for apps/libs):

# Install poetry (one-liner; follow official docs for latest)
curl -sSL https://install.python-poetry.org | python3 -

# Create new project
poetry new myproj
cd myproj

# Let Poetry create and manage the venv, add deps
poetry add requests
poetry shell   # spawn a shell in the venv
poetry run python -m myproj

Poetry uses pyproject.toml for config and makes publishing easier.


Best practices for projects

  • Use a project-local venv (e.g., .venv) and add it to .gitignore.
  • Pin direct dependencies in requirements.txt or use pyproject.lock (Poetry). Don’t commit large site-packages.
  • Prefer python -m venv .venv over system package managers.
  • Use virtual environments for both development and CI to ensure parity.
  • For quick CLI tools, prefer pipx.

Example .gitignore snippet:

.venv/
venv/
__pycache__/
*.pyc

Working with multiple Python versions

Use pyenv (or system-installed interpreters) to install multiple Python versions, then create venvs from each version:

# Example with a python3.10 interpreter already installed
python3.10 -m venv .venv-py310
source .venv-py310/bin/activate
python --version

CI tips (GitHub Actions example)

A minimal workflow to reproduce environment using requirements.txt:

name: Python CI
on: [push]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: '3.11'
      - name: Install dependencies
        run: |
          python -m venv .venv
          source .venv/bin/activate
          pip install -r requirements.txt
      - name: Run tests
        run: |
          source .venv/bin/activate
          pytest

(Use the actions/cache action to cache pip downloads for faster builds.)

Troubleshooting

  • “pip not found” after activation: ensure you activated the venv in the same shell; on Windows prefer PowerShell activation or use .\.venv\Scripts\python -m pip.
  • Wrong Python version: create the venv with the desired python executable (python3.9 -m venv .venv).
  • Dependencies missing in production: make sure you froze exact versions and installed them in the deployment environment.

When not to use virtual environments

  • Single short-lived script executed once on your machine may not need a venv.
  • If you’re using system packages intentionally (e.g., system-wide daemon with distro-managed packages), coordinate with system package manager instead.

Short checklist before shipping a Python project

  • Add .venv/ (or chosen venv folder) to .gitignore
  • Commit requirements.txt or poetry.lock / pyproject.toml
  • Document how to create and activate the venv in README
  • Use pipx for global CLIs and Poetry for app dependency management

Summary

Virtual environments are a fundamental tool for clean, reproducible Python development. Use python -m venv for simple projects, pipx for isolated CLIs, and Poetry if you want an all-in-one dependency and packaging workflow. Activate the venv, install packages, freeze your dependencies, and you’ll avoid “it works on my machine” problems.