Table of Contents

virtualenv is a tool to create isolated Python environments, allowing different projects to have separate dependencies without conflicts. It's one of the most widely used tools in the Python ecosystem for dependency isolation and project management.

Overview

virtualenv creates isolated Python environments by copying or linking the Python binary and creating a directory structure that houses separate installations of libraries and dependencies. This isolation prevents conflicts between project dependencies and protects the system Python installation from modifications.

Unlike the built-in venv module (available in Python 3.3+), virtualenv:

  • Works with older Python versions (2.7+)
  • Creates environments faster in many scenarios
  • Offers more configuration options and features
  • Provides better cross-platform consistency
  • Supports discovery of different Python interpreters
  • Has a more active development and feature set

Key Features

Environment Isolation

  • Separate package installations: Each environment has its own site-packages
  • Python version control: Different environments can use different Python versions
  • Dependency independence: Projects don't interfere with each other
  • System protection: System Python remains untouched

Flexibility

  • Multiple Python versions: Easily switch between Python 2.7, 3.x versions
  • Customizable environments: Configure environment behavior extensively
  • Seed packages: Pre-install packages during creation
  • Custom prompts: Personalize shell prompts per environment

Performance

  • Fast creation: Optimized environment setup
  • Symlink support: Option to symlink instead of copy for speed
  • App data integration: Reuses pip and setuptools across environments

Cross-Platform

  • Windows, macOS, Linux: Consistent behavior across platforms
  • Shell support: Works with bash, zsh, fish, PowerShell, cmd
  • Path handling: Robust path management on all systems

Installation

Using pip

# Install virtualenv
pip install virtualenv

# Or install for user only
pip install --user virtualenv

# Install specific version
pip install virtualenv==20.25.0

Using package managers

# Ubuntu/Debian
sudo apt-get install python3-virtualenv

# Fedora/RHEL
sudo dnf install python3-virtualenv

# macOS with Homebrew
brew install virtualenv

# Arch Linux
sudo pacman -S python-virtualenv

Verify Installation

# Check version
virtualenv --version

# Show help
virtualenv --help

Basic Usage

Creating Virtual Environments

# Create environment with default Python
virtualenv myenv

# Create with specific Python version
virtualenv -p python3.11 myenv

# Create with full path to Python
virtualenv -p /usr/bin/python3.11 myenv

# Create in current directory
virtualenv .

# Create with custom name
virtualenv my-project-env

Activating Environments

Linux/macOS

# Activate environment
source myenv/bin/activate

# Shorter alternative
. myenv/bin/activate

# Check activation (prompt changes)
which python

Windows

# Command Prompt
myenv\Scripts\activate.bat

# PowerShell
myenv\Scripts\Activate.ps1

Fish Shell

# Fish shell activation
source myenv/bin/activate.fish

Csh/Tcsh

# Csh/tcsh activation
source myenv/bin/activate.csh

Deactivating Environments

# Deactivate current environment (works on all platforms)
deactivate

# Shell returns to system Python

Basic Workflow

# 1. Create environment
virtualenv myproject

# 2. Activate
source myproject/bin/activate

# 3. Install packages
pip install requests flask numpy

# 4. Work on project
python app.py

# 5. Freeze dependencies
pip freeze > requirements.txt

# 6. Deactivate when done
deactivate

Advanced Features

Python Version Selection

# Use specific Python version
virtualenv -p python3.9 env39
virtualenv -p python3.11 env311

# Use pyenv Python
virtualenv -p ~/.pyenv/versions/3.11.5/bin/python myenv

# Discover Python by version
virtualenv --python=3.11 myenv

# List available Python interpreters
virtualenv --python-list

Environment Options

# No pip (minimal environment)
virtualenv --no-pip myenv

# No setuptools
virtualenv --no-setuptools myenv

# No wheel
virtualenv --no-wheel myenv

# Download packages
virtualenv --download myenv

# Never download (use bundled)
virtualenv --never-download myenv

# Copy files instead of symlink
virtualenv --always-copy myenv

# System site-packages access
virtualenv --system-site-packages myenv

Custom Prompts

# Custom prompt prefix
virtualenv --prompt="[MyProject] " myenv

# Custom prompt with interpolation
virtualenv --prompt="({project_name}) " myenv

# Disable prompt modification
virtualenv --no-prompt myenv

Seeding Packages

# Pre-install packages
virtualenv --seed-app-data=yes myenv

# Use specific pip version
virtualenv --pip=20.3.4 myenv

# Use specific setuptools version
virtualenv --setuptools=65.0.0 myenv

Configuration

Configuration Files

virtualenv reads configuration from:

  1. Environment variable: VIRTUALENV_CONFIG_FILE
  2. Local config: $PWD/virtualenv.ini or $PWD/.virtualenv
  3. User config (Unix): ~/.config/virtualenv/virtualenv.ini
  4. User config (macOS): ~/Library/Application Support/virtualenv/virtualenv.ini
  5. User config (Windows): %APPDATA%\virtualenv\virtualenv.ini

Example Configuration

Create ~/.config/virtualenv/virtualenv.ini:

[virtualenv]
# Use Python 3.11 by default
python = /usr/bin/python3.11

# Always copy files
always-copy = true

# Custom prompt
prompt = ({project_name})

# Download packages
download = true

# Include system site-packages
system-site-packages = false

# Don't modify prompt
no-prompt = false

Environment Variables

# Custom config file location
export VIRTUALENV_CONFIG_FILE=/path/to/config.ini

# Override Python version
export VIRTUALENV_PYTHON=/usr/bin/python3.11

# Set download behavior
export VIRTUALENV_DOWNLOAD=true

# Set prompt
export VIRTUALENV_PROMPT="[MyProject] "

Project Workflows

Starting a New Project

# 1. Create project directory
mkdir myproject
cd myproject

# 2. Initialize Git
git init

# 3. Create virtual environment
virtualenv .venv

# 4. Add to .gitignore
echo ".venv/" >> .gitignore

# 5. Activate environment
source .venv/bin/activate

# 6. Install dependencies
pip install flask requests sqlalchemy

# 7. Freeze requirements
pip freeze > requirements.txt

# 8. Commit
git add .gitignore requirements.txt
git commit -m "Initial project setup"

Joining an Existing Project

# 1. Clone repository
git clone https://github.com/company/project.git
cd project

# 2. Create virtual environment
virtualenv .venv

# 3. Activate
source .venv/bin/activate

# 4. Install dependencies
pip install -r requirements.txt

# 5. Verify setup
python manage.py check
pytest

Multiple Environments

# Create environments for different Python versions
virtualenv -p python3.9 .venv-py39
virtualenv -p python3.10 .venv-py310
virtualenv -p python3.11 .venv-py311

# Test across versions
source .venv-py39/bin/activate
pytest
deactivate

source .venv-py310/bin/activate
pytest
deactivate

source .venv-py311/bin/activate
pytest
deactivate

Development vs Production

# Development environment
virtualenv .venv-dev
source .venv-dev/bin/activate
pip install -r requirements-dev.txt

# Production environment (minimal)
virtualenv .venv-prod
source .venv-prod/bin/activate
pip install -r requirements.txt

virtualenv vs venv

Feature Comparison

Feature virtualenv venv
Python Version 2.7+ and 3.3+ 3.3+ only
Included with Python No (pip install) Yes (built-in)
Speed Faster (typically) Moderate
Python Discovery Advanced Basic
Configuration Extensive Limited
Multiple Python Versions Excellent Limited
Upgrade Path Regular updates Python version tied
Features More features Minimal

When to Use virtualenv

Use virtualenv when:

  • Supporting Python 2.7 or older Python 3.x
  • Need faster environment creation
  • Require advanced configuration options
  • Working with multiple Python versions
  • Want latest features and updates
  • Need better cross-platform consistency
  • Using tools that integrate with virtualenv

When to Use venv

Use venv when:

  • Python 3.3+ is sufficient
  • Prefer built-in tools (no external dependencies)
  • Want simpler, minimal setup
  • Following official Python recommendations
  • Don't need advanced features

Command Comparison

# virtualenv
virtualenv myenv
source myenv/bin/activate

# venv
python -m venv myenv
source myenv/bin/activate

# Both have similar activation/deactivation

Integration with Tools

pip Integration

# Create and install in one step
virtualenv myenv && source myenv/bin/activate && pip install -r requirements.txt

# Upgrade pip in environment
pip install --upgrade pip

# Install editable packages
pip install -e /path/to/package

IDE Integration

VS Code

// .vscode/settings.json
{
  "python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
  "python.terminal.activateEnvironment": true
}

PyCharm

  1. File → Settings → Project → Python Interpreter
  2. Add Interpreter → Virtualenv Environment
  3. Select existing environment or create new

Vim/Neovim

" Activate virtualenv in vim
let g:python3_host_prog = '/path/to/.venv/bin/python'

Shell Integration

Bash/Zsh

# Add to ~/.bashrc or ~/.zshrc
# Auto-activate virtualenv when entering directory
function cd() {
  builtin cd "$@"
  if [[ -f .venv/bin/activate ]]; then
    source .venv/bin/activate
  fi
}

Fish Shell Alternative

# Add to ~/.config/fish/config.fish
function cd
  builtin cd $argv
  if test -f .venv/bin/activate.fish
    source .venv/bin/activate.fish
  end
end

Docker Integration

FROM python:3.11-slim

# Install virtualenv
RUN pip install virtualenv

WORKDIR /app

# Create virtual environment
RUN virtualenv /opt/venv

# Activate virtual environment
ENV PATH="/opt/venv/bin:$PATH"

# Install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

CMD ["python", "app.py"]

Advanced Use Cases

Relocatable Environments

# Create relocatable environment
virtualenv --relocatable myenv

# Move environment
mv myenv /new/location/myenv

# Reactivate
source /new/location/myenv/bin/activate

Note: Relocatable environments have limitations and aren't recommended for production use.

Shared Environments

# Create environment in shared location
virtualenv /shared/envs/myproject

# Team members activate
source /shared/envs/myproject/bin/activate

# Better: Use requirements.txt instead
pip freeze > requirements.txt
# Share requirements.txt, everyone creates own environment

Testing Multiple Python Versions

# Create test script
cat > test_versions.sh << 'EOF'
#!/bin/bash
for version in 3.9 3.10 3.11 3.12; do
  echo "Testing Python $version"
  virtualenv -p python$version .venv-$version
  source .venv-$version/bin/activate
  pip install -r requirements.txt
  pytest
  deactivate
  rm -rf .venv-$version
done
EOF

chmod +x test_versions.sh
./test_versions.sh

Custom Python Builds

# Use custom compiled Python
virtualenv -p /opt/python-3.11-custom/bin/python myenv

# Use Python with optimizations
virtualenv -p /usr/local/bin/python3.11-optimized myenv

Troubleshooting

Common Issues

Environment Not Activating

Problem: source myenv/bin/activate doesn't work

Solutions:

# Check if file exists
ls -la myenv/bin/activate

# Use full path
source /full/path/to/myenv/bin/activate

# Check shell
echo $SHELL

# Try alternative activation
. myenv/bin/activate

# Windows PowerShell: Enable scripts
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Wrong Python Version

Problem: Environment uses wrong Python version

Solutions:

# Check Python in environment
which python
python --version

# Recreate with specific Python
rm -rf myenv
virtualenv -p python3.11 myenv

# Verify
source myenv/bin/activate
python --version

Permission Errors

Problem: Cannot create environment due to permissions

Solutions:

# Use --user for virtualenv installation
pip install --user virtualenv

# Create in home directory
virtualenv ~/myenv

# Check directory permissions
ls -la /path/to/project

# Avoid sudo
# Don't use: sudo virtualenv myenv

pip Not Found

Problem: pip not available in environment

Solutions:

# Create with pip explicitly
virtualenv --pip myenv

# Install pip manually
source myenv/bin/activate
python -m ensurepip
python -m pip install --upgrade pip

# Verify
which pip
pip --version

SSL Certificate Errors

Problem: SSL errors when creating environment

Solutions:

# Use system certificates
virtualenv --never-download myenv

# Or update certificates
pip install --upgrade certifi

# Set certificate path
export SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt
virtualenv myenv

Debug Mode

# Verbose output
virtualenv -vvv myenv

# Show more information
virtualenv --verbose myenv

# Check system info
virtualenv --system

Performance Optimization

Fast Environment Creation

# Use symlinks (faster)
virtualenv myenv  # Default on Unix

# Explicit symlink
virtualenv --symlinks myenv

# Copy only when needed
virtualenv --always-copy myenv  # Slower but more portable

Caching

# Check app data location
virtualenv --app-data

# Clear cache
rm -rf ~/.local/share/virtualenv/*

# Use specific app data
virtualenv --app-data /tmp/venv-cache myenv

Parallel Environments

# Create multiple environments in parallel
virtualenv env1 & \
virtualenv env2 & \
virtualenv env3 & \
wait

Best Practices

Do's

Use descriptive environment names: .venv, venv, or project-specific ✅ Add to .gitignore: Never commit environments to version control ✅ Use requirements.txt: Share dependencies, not environments ✅ Activate before installing: Always activate before pip installKeep environments small: Only install needed packages ✅ Recreate when needed: Environments are disposable ✅ Document dependencies: Maintain accurate requirements.txt ✅ Use virtual environments: Even for simple scripts

Don'ts

Don't commit environments: Add to .gitignore ❌ Don't use sudo: Install virtualenv with pip, not system package manager ❌ Don't move environments: Recreate instead ❌ Don't share environments: Each developer creates their own ❌ Don't install globally: Use virtual environments ❌ Don't mix Python versions: One version per environment ❌ Don't activate base: Keep system Python clean

Project Structure

myproject/
├── .venv/              # Virtual environment (in .gitignore)
├── .gitignore          # Includes .venv/
├── README.md           # Setup instructions
├── requirements.txt    # Production dependencies
├── requirements-dev.txt # Development dependencies
├── src/               # Source code
│   └── myproject/
├── tests/             # Tests
└── setup.py           # Package configuration

.gitignore Template

# Virtual environments
.venv/
venv/
ENV/
env/
.virtualenv/

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

CI/CD Integration

GitHub Actions

name: CI
on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: ['3.9', '3.10', '3.11']
    
    steps:
      - uses: actions/checkout@v4
      
      - name: Set up Python
        uses: actions/setup-python@v4
        with:
          python-version: ${{ matrix.python-version }}
      
      - name: Install virtualenv
        run: pip install virtualenv
      
      - name: Create virtual environment
        run: virtualenv .venv
      
      - name: Install dependencies
        run: |
          source .venv/bin/activate
          pip install -r requirements.txt
          pip install -r requirements-dev.txt
      
      - name: Run tests
        run: |
          source .venv/bin/activate
          pytest
          
      - name: Lint
        run: |
          source .venv/bin/activate
          ruff check .

GitLab CI

stages:
  - test

test:
  stage: test
  image: python:3.11
  before_script:
    - pip install virtualenv
    - virtualenv .venv
    - source .venv/bin/activate
    - pip install -r requirements.txt
  script:
    - pytest
    - coverage report
  cache:
    paths:
      - .venv/

Jenkins

pipeline {
  agent any
  
  stages {
    stage('Setup') {
      steps {
        sh 'pip install virtualenv'
        sh 'virtualenv .venv'
        sh 'source .venv/bin/activate && pip install -r requirements.txt'
      }
    }
    
    stage('Test') {
      steps {
        sh 'source .venv/bin/activate && pytest'
      }
    }
  }
}

Migration Guides

From System Python

# 1. Document current packages
pip freeze > old-requirements.txt

# 2. Create virtual environment
virtualenv .venv

# 3. Activate
source .venv/bin/activate

# 4. Install needed packages
pip install -r requirements.txt

# 5. Test application
python app.py

# 6. Document in README
echo "Setup: virtualenv .venv && source .venv/bin/activate && pip install -r requirements.txt" >> README.md

From venv to virtualenv

# 1. Export from venv
source venv/bin/activate
pip freeze > requirements.txt
deactivate

# 2. Create with virtualenv
virtualenv .venv

# 3. Install dependencies
source .venv/bin/activate
pip install -r requirements.txt

# 4. Verify
python app.py

# 5. Remove old venv
rm -rf venv/

From conda to virtualenv

# 1. Export conda environment
conda list --export > conda-packages.txt

# 2. Extract pip packages
conda list --export | grep pypi > requirements.txt

# 3. Create virtualenv
virtualenv .venv

# 4. Activate and install
source .venv/bin/activate
pip install -r requirements.txt

# 5. Add conda-specific packages manually
pip install numpy  # etc.

Automation and Helpers

Automatic Activation

direnv

# Install direnv
# Ubuntu/Debian: sudo apt-get install direnv
# macOS: brew install direnv

# Add to shell config
eval "$(direnv hook bash)"  # For bash
eval "$(direnv hook zsh)"   # For zsh

# Create .envrc in project
echo 'layout python' > .envrc

# Allow directory
direnv allow

# Auto-activates when entering directory

autoenv

# Install
pip install autoenv

# Add to ~/.bashrc
source ~/.autoenv/activate.sh

# Create .env file
echo 'source .venv/bin/activate' > .env

# Auto-activates when entering directory

Wrapper Scripts

# Create activate.sh
cat > activate.sh << 'EOF'
#!/bin/bash
if [ ! -d ".venv" ]; then
  echo "Creating virtual environment..."
  virtualenv .venv
  source .venv/bin/activate
  pip install -r requirements.txt
else
  source .venv/bin/activate
fi
EOF

chmod +x activate.sh

# Use it
./activate.sh

Make Targets

# Makefile
.PHONY: venv install test clean

venv:
    virtualenv .venv
    source .venv/bin/activate && pip install --upgrade pip

install: venv
    source .venv/bin/activate && pip install -r requirements.txt

test:
    source .venv/bin/activate && pytest

clean:
    rm -rf .venv
    find . -type d -name __pycache__ -exec rm -rf {} +
    find . -type f -name "*.pyc" -delete

Usage:

make install  # Setup environment
make test     # Run tests
make clean    # Remove environment

See Also

Additional Resources

Official Documentation

Community Resources

Tutorials

  • virtualenvwrapper - Wrapper for managing multiple virtualenvs
  • pyenv - Python version management
  • pipx - Install Python applications in isolated environments
  • tox - Test automation across environments