Python virtual environments solve one of the most common problems in Python development: dependency conflicts between projects. When Project A needs Django 4.2 and Project B needs Django 5.0, installing both globally breaks one of them. Virtual environments create isolated Python installations where each project has its own packages, its own versions, and its own pip — completely independent from each other and from your system Python. This guide covers everything from creating your first environment through production deployment patterns.

Prerequisites

  • Python 3.3 or later installed (python3 --version to check)
  • Basic familiarity with the command line (terminal, shell, or PowerShell)
  • A text editor or IDE for Python development
  • pip available (included with Python 3.4+ by default)

Creating Virtual Environments with venv

venv is Python’s built-in module for creating virtual environments. It ships with Python 3.3+ and requires no additional installation.

Basic Creation

# Create a virtual environment in the .venv directory
python3 -m venv .venv

# On some systems, you may need to install the venv package first
# Debian/Ubuntu:
sudo apt install python3-venv

# Verify the environment was created
ls .venv/
# Output: bin/  include/  lib/  pyvenv.cfg

The .venv directory name is a convention — you can name it anything, but .venv is the most common choice. The leading dot keeps it hidden in Unix directory listings and most .gitignore templates already exclude it.

What venv Creates

.venv/
├── bin/                    # Activation scripts and executables (Linux/macOS)
│   ├── activate            # Bash activation script
│   ├── activate.csh        # C-shell activation
│   ├── activate.fish       # Fish shell activation
│   ├── pip                 # Isolated pip
│   ├── pip3                # Symlink to pip
│   └── python3             # Symlink to the Python interpreter
├── include/                # C headers for building extensions
├── lib/python3.x/
│   └── site-packages/      # Where pip installs packages
└── pyvenv.cfg              # Environment configuration

On Windows, the structure is similar but uses Scripts/ instead of bin/ and .exe extensions.

Activating the Environment

Activation modifies your shell’s PATH so that python and pip point to the virtual environment’s copies instead of the system-wide ones.

# Linux / macOS (Bash/Zsh)
source .venv/bin/activate

# Linux (Fish shell)
source .venv/bin/activate.fish

# Windows (Command Prompt)
.venv\Scripts\activate.bat

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

When activated, your prompt changes to show the environment name:

(.venv) user@hostname:~/myproject$

Verify the environment is active:

# Check which Python is being used
which python3
# Output: /home/user/myproject/.venv/bin/python3

# Check which pip is being used
which pip
# Output: /home/user/myproject/.venv/bin/pip

# The system Python is untouched
python3 -c "import sys; print(sys.prefix)"
# Output: /home/user/myproject/.venv

Deactivating the Environment

deactivate

This restores your PATH to its previous state. The virtual environment remains on disk — deactivating does not delete anything.

Managing Packages with pip

With the virtual environment activated, pip installs packages only into that environment.

Installing Packages

# Install a specific package
pip install requests

# Install a specific version
pip install requests==2.31.0

# Install with a version constraint
pip install "requests>=2.28,<3.0"

# Install multiple packages
pip install flask sqlalchemy redis

# Upgrade a package
pip install --upgrade requests

# Install from a Git repository
pip install git+https://github.com/user/repo.git@main

Listing and Inspecting Packages

# List all installed packages
pip list

# Show detailed info about a package
pip show requests

# Check for outdated packages
pip list --outdated

# Show dependency tree (install pipdeptree first)
pip install pipdeptree
pipdeptree

Uninstalling Packages

# Remove a single package
pip uninstall requests

# Remove a package without confirmation prompt
pip uninstall -y requests

Working with requirements.txt

requirements.txt is the standard way to declare and share Python project dependencies. It lists packages and their versions so anyone can recreate the same environment.

Generating requirements.txt

# Export all installed packages with exact versions
pip freeze > requirements.txt

The output looks like this:

certifi==2024.2.2
charset-normalizer==3.3.2
idna==3.6
requests==2.31.0
urllib3==2.2.1

Installing from requirements.txt

# Create a new environment and install dependencies
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt

Best Practices for requirements.txt

# Pin exact versions for production (reproducible builds)
requests==2.31.0
flask==3.0.2

# Use >= for library development (allow compatible updates)
requests>=2.28

# Separate dev dependencies into a second file
# requirements-dev.txt:
-r requirements.txt
pytest==8.0.0
black==24.2.0
mypy==1.8.0
# Install dev dependencies (includes production deps too)
pip install -r requirements-dev.txt

Real-World Scenario: Dependency Conflict Resolution

You join a team working on a web application. You clone the repo, create a virtual environment, and run pip install -r requirements.txt. It fails with a version conflict:

ERROR: pip's dependency resolver does not currently take into account all the packages that are installed.
Package A 2.0 requires LibX>=3.0, but you have LibX 2.5 which is incompatible.

How to fix it:

# See what requires the conflicting package
pip install pipdeptree
pipdeptree --reverse --packages LibX

# Option 1: Upgrade the conflicting package
pip install --upgrade LibX

# Option 2: Find compatible versions
pip install "PackageA>=2.0" "PackageB>=1.0" --dry-run

# Regenerate requirements.txt with the resolved versions
pip freeze > requirements.txt

Comparing Python Environment Tools

FeaturevenvvirtualenvcondaPoetry
Built into PythonYes (3.3+)No (pip install)No (separate installer)No (pip install)
SpeedModerateFastSlowModerate
Python version managementNoNoYesNo (use pyenv)
Non-Python dependenciesNoNoYes (C libs, R, etc.)No
Lock file supportNoNoenvironment.ymlpoetry.lock
Dependency resolutionpip (basic)pip (basic)conda solverAdvanced
Disk usage per env~20 MB~20 MB~500 MB+~20 MB
Best forStandard Python projectsLegacy Python 2 supportData science, ML, cross-languageModern Python packages with strict deps

Use venv for standard Python projects — it is the official tool, requires nothing extra, and works everywhere Python runs. Use conda when you need non-Python dependencies (NumPy with BLAS, CUDA, R packages). Use Poetry when you need strict dependency resolution and a modern workflow for publishing packages.

Virtual Environments in CI/CD and Docker

CI/CD Pipelines (GitHub Actions Example)

# .github/workflows/test.yml
name: Tests
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with:
          python-version: "3.12"
      - name: Install dependencies
        run: |
          python -m venv .venv
          source .venv/bin/activate
          pip install -r requirements.txt
          pip install -r requirements-dev.txt
      - name: Run tests
        run: |
          source .venv/bin/activate
          pytest

Docker (Multi-Stage Build)

# Build stage
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN python -m venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
RUN pip install --no-cache-dir -r requirements.txt

# Production stage
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /opt/venv /opt/venv
ENV PATH="/opt/venv/bin:$PATH"
COPY . .
CMD ["python", "app.py"]

Using a virtual environment inside Docker is debatable — the container already provides isolation. However, multi-stage builds with venv produce smaller images because the build tools and pip cache stay in the builder stage.

Gotchas and Edge Cases

Python version mismatch: A virtual environment is tied to the Python version that created it. If you upgrade Python from 3.11 to 3.12, existing environments may break. Recreate them after major Python upgrades.

--system-site-packages leaks: Creating an environment with python3 -m venv --system-site-packages .venv gives access to globally installed packages. This is useful for packages that are hard to install via pip (like system-provided PyGObject), but it means pip freeze includes system packages, polluting your requirements.txt. Use pip freeze --local to list only environment-specific packages.

pip cache fills disk: pip caches downloaded packages in ~/.cache/pip/. On build servers, this grows unbounded. Use pip install --no-cache-dir or periodically run pip cache purge.

Activation is shell-specific: If you use source .venv/bin/activate in a script that runs in a subshell, the activation does not persist. Instead, call the Python binary directly: .venv/bin/python script.py or .venv/bin/pip install package.

Windows PowerShell execution policy: By default, PowerShell blocks running scripts including activation. Fix it once per user:

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Shared network drives and virtual environments: Virtual environments use symlinks to the Python interpreter. Some network filesystems (SMB, NFS) do not support symlinks, causing the environment to fail. Create environments on local disk only.

Troubleshooting Common Issues

”No module named venv"

# Debian/Ubuntu — install the venv module
sudo apt install python3-venv

# Some distributions ship Python without venv
# Verify it is available:
python3 -m venv --help

"pip install” fails with permission errors

# If you see "Permission denied" — you probably forgot to activate
source .venv/bin/activate
pip install requests

# NEVER use sudo pip install — it modifies system packages
# If you need system-wide packages, use apt/dnf instead

Environment uses wrong Python version

# Specify the Python version when creating the environment
python3.12 -m venv .venv

# Or use the full path
/usr/bin/python3.12 -m venv .venv

# Verify the version inside the environment
source .venv/bin/activate
python --version

packages installed globally instead of in the environment

# Check that pip belongs to the environment
which pip
# Should show: .venv/bin/pip

# If it shows /usr/bin/pip — the environment is not activated
source .venv/bin/activate

Summary

  • python3 -m venv .venv creates an isolated Python environment — each project gets its own packages without affecting other projects or the system Python
  • Activate with source .venv/bin/activate to make the environment’s Python and pip the defaults in your current shell session
  • pip freeze > requirements.txt captures exact dependency versions — share this file in version control so others can recreate the identical environment
  • pip install -r requirements.txt inside a fresh environment reproduces the dependency set — always pin versions with == for production deployments
  • Never use sudo pip install — it modifies system packages and creates conflicts. Virtual environments eliminate the need for root access entirely
  • Recreate environments after Python upgrades — they are tied to the Python version that created them and may break on major version changes