Definition
Installing a library with pip drops it somewhere on the machine, and by default that place is a single one: the system Python. The trouble starts as soon as a second project needs a different version of the same library. Both fight over the same folder, the latest install overwrites the previous one, and one of the two projects starts failing without anything having changed in its own code.
venv answers that problem by giving each project its own folder: a copy of the interpreter plus a stock of libraries that belong to that project alone. It is the standard library module that creates this virtual environment, introduced by PEP 405 and shipped with Python since version 3.3: nothing to download, nothing to install before using it.
Creating one takes a single command, followed by a second one that activates the environment.
python -m venv .venv
source .venv/bin/activate
.venv\Scripts\activateThe second line applies to macOS and Linux, the third to Windows. Once the environment is active, pip install drops libraries into that folder instead of the system Python, which settles exactly the conflict described above. The environment name then shows up at the start of the terminal prompt, a simple visual cue.
What the folder actually holds
Venv does nothing sophisticated: it creates a tree of ordinary files and adjusts a single setting.
| Item | Role |
|---|---|
bin/ or Scripts/ | The interpreter and the installed commands |
lib/.../site-packages/ | The libraries downloaded from PyPI |
pyvenv.cfg | The version and path of the original Python |
Activating the environment does exactly one thing: it puts its executables folder at the front of the PATH, so that python and pip point at the ones inside the environment rather than the system ones. That is also why activation can be skipped entirely: calling .venv/bin/python directly produces the same result, which is what most deployment scripts do.
The command to leave the environment is deactivate, added automatically by venv: nothing extra to install to get it.
venv against its alternatives
The question comes back with every new project: does venv suffice, or is a fuller tool needed? The answer depends on what the project actually requires.
| Tool | What it adds | What it costs |
|---|---|---|
venv | Nothing to install, available everywhere | Handles neither Python versions nor dependency locking |
virtualenv | Faster, compatible with older Python releases | One more external dependency to install |
| poetry | Environment, dependencies and publishing in one piece | A configuration format and habits to learn |
conda | Also installs compiled non-Python libraries | A parallel ecosystem, heavy outside scientific computing |
For an exercise, a script, a personal project or a repository others will clone, venv is enough and carries the advantage of being understood by everyone. A fuller tool earns its place mostly when the project becomes a published package, or when several machines must end up with exactly the same versions.
The mistakes of the first weeks
Most of the trouble people run into with venv comes down to an easy slip made early on, not to the tool itself.
Installing a library without having activated the environment is the most common mistake. pip does install something, but into the system Python, not the project folder, and the program then fails with a ModuleNotFoundError on the first import.
The reflex that settles the question holds two checks: which Python answers, and where it installs.
which python
python -m pip install requestsFrom the REPL, reading sys.executable gives the same answer with no ambiguity: if the printed path does not run through the project folder, the environment is not active.
A second mistake is pushing the .venv folder into the Git repository. It is heavy, it holds absolute paths tied to a single machine, and it is useless to anybody else. What actually gets shared is the requirements.txt, which rebuilds the environment in a single command.
A third mistake comes from a project folder that gets moved or renamed: the scripts in the executables folder keep the original absolute path in memory and stop working. The fix deserves no effort at all: delete the folder and recreate it.
When it is of no use
A virtual environment isolates dependencies from one another. A script that only imports the standard library has nothing to isolate, and creating a venv out of habit lengthens the setup without protecting anything.
Containers are the more debated case. A Docker image runs a single application, and isolation already exists at the level of the image: many teams install libraries straight into the container's Python. Others still keep a virtual environment, so the launch command stays identical locally and in production.
Frequently asked questions
One environment per project, or a single one for everything?
One per project, and that is the whole point of the approach. Two projects may require two incompatible versions of the same library, and a shared environment brings back exactly the problem venv is meant to remove. The cost is nil: an environment is recreated in a few seconds.
Can the Python version of the environment be chosen?
Yes, but indirectly: venv takes the version of the interpreter that created it. The command python3.12 -m venv .venv yields a 3.12 environment, provided that version is already installed on the machine. Installing several Python versions remains the job of another tool, such as pyenv.
Is activation really mandatory?
No, it is only a convenience. Calling .venv/bin/python my_script.py produces the same result without changing anything in the terminal, and it is the form used in scheduled jobs, containers and pytest commands launched by a continuous integration tool.