python -m venv: How to Create and Use Python Virtual Environments
If you have ever upgraded a library for one project and watched a completely unrelated project break, you have already met the problem `python -m venv` exists to solve. A Python virtual environment is an isolated Python environment with its own packages, kept entirely separate from your system Python and from every other project on the machine. You create one with a single command, activate it, install whatever that project needs, and the rest of your system stays clean.
This guide is the practical, command-by-command version: what a virtual environment actually is, why you need one, how to create, activate, populate, and deactivate it, and how the exact same tool carries over to a real server when you deploy. Heavy on code, because that is how you learn this.
Key Takeaways
• A virtual environment is an isolated Python install with its own `python`, `pip`, and packages, separate from the system Python.
• Create one with `python -m venv venv` (or `.venv`) inside your project folder.
• Activate it with `source venv/bin/activate` on Mac/Linux or `venv\Scripts\activate` on Windows.
• Install per project, then pin with `pip freeze > requirements.txt` for reproducible deploys.
• One venv per project and never `pip install` into the global Python — that single rule prevents most Python environment pain.
• The same `venv` workflow runs on your server, which is why you want a host that gives you full control over the Python runtime.
What is a Python virtual environment?
A Python virtual environment is a self-contained directory that holds its own copy (or link) of the Python interpreter plus its own `site-packages` folder where libraries get installed. When the environment is active, running `python` and `pip` uses *that* environment’s interpreter and *that* environment’s packages — not the ones installed system-wide.
Think of it as a sealed box per project. Inside the box, you can install Django 4.2 for one app and Django 5.1 for another, and neither knows the other exists. The system Python that your operating system depends on is never touched.
The tool is built into Python 3.3 and later as the standard library `venv` module. You invoke it through the interpreter:
“`bash python -m venv venv “`
That is the canonical form of the command, and the reason this article is named after it. `python -m venv` means “run the `venv` module as a script,” and it is the officially recommended way to create a virtual environment python setup.
Why do you need a virtual environment?
Without isolation, every Python project on your machine shares one set of installed packages — the global `site-packages` of the system Python. That sounds simpler until you have a second project. Here is the failure mode:
| Scenario | Without a venv | With a venv |
|---|---|---|
| Project A needs `requests` 2.25, Project B needs 2.32 | Impossible — only one version can be installed | Each project gets its own version |
| Upgrade a library for one app | Silently changes it for every app | Affects only the active environment |
| Reproduce dependencies on a server | Guesswork; “works on my machine” | `requirements.txt` rebuilds it exactly |
| System Python stays clean | No — it accumulates project cruft | Yes — untouched |
The three concrete reasons you want one:
- Avoid dependency conflicts between projects. Project A pins `numpy` 1.26, Project B needs 2.1. With a venv each gets what it asks for.
- Keep the system Python clean. Your OS and its tooling may depend on the system interpreter. Installing project packages there is how you eventually break `apt`, `yum`, or a system utility written in Python.
- Reproducible per-project dependencies. Freeze the exact versions into a file, commit it, and anyone (including your production server) can rebuild the same environment.
How do you create a virtual environment with python -m venv?
Navigate into your project folder and run the create command. The final argument is the *name of the directory* the environment will live in — `venv` and `.venv` are the two common conventions:
“`bash
cd ~/projects/my-app
python -m venv venv “`
Many developers prefer a dot-prefixed name so the folder is hidden and clearly “tooling, not source”:
“`bash python -m venv .venv “`
On systems where `python` points at Python 2, or where multiple versions are installed, be explicit:
“`bash python3 -m venv .venv
python3.12 -m venv .venv “`
After this runs, you have a new folder containing `bin/` (or `Scripts/` on Windows), a private `python`, a private `pip`, and an empty `site-packages`. Nothing is active yet — creating is not the same as using.
How do you activate a virtual environment?
Activation is the step that points your shell at the environment’s interpreter. The command differs by operating system because the directory layout differs.
Mac / Linux:
“`bash source venv/bin/activate “`
Windows (Command Prompt):
“`bat venv\Scripts\activate “`
Windows (PowerShell):
“`powershell venv\Scripts\Activate.ps1 “`
Once activated, your prompt changes to show the environment name in parentheses, a constant reminder of where `pip install` will land:
“`bash (venv) ~/projects/my-app $ “`
What does activation actually do? It prepends the environment’s `bin`/`Scripts` directory to your shell’s `PATH` and sets `VIRTUAL_ENV`. That means `python` and `pip` now resolve to the venv’s copies *first*. You can confirm it:
“`bash
which python which pip
where python “`
If those paths point inside your project’s `venv` folder, you are isolated and ready to install.
How do you install packages into a virtual environment?
With the environment active, `pip` installs into the venv’s private `site-packages` — the global Python is never touched:
“`bash
pip install requests
pip install flask gunicorn psycopg2-binary
pip install “django==5.1.*” “`
Check what is installed inside the box at any time:
“`bash pip list “`
Now the part that makes environments reproducible. Freeze the exact installed versions into a `requirements.txt` file:
“`bash pip freeze > requirements.txt “`
That file is plain text, looks like this, and belongs in version control:
“`text Django==5.1.4 gunicorn==23.0.0 psycopg2-binary==2.9.10 “`
Anyone — a teammate, your CI pipeline, your production server — can recreate the identical environment by activating a fresh venv and running:
“`bash pip install -r requirements.txt “`
This is the whole reproducibility story: a fresh venv plus `requirements.txt` rebuilds the same set of packages, every time, on any machine.
The mental shift that makes virtual environments finally click is realizing that “installing a Python package” is the wrong default — installing it *globally*, into the system Python, is what causes the dependency hell that `venv` exists to prevent. Without a venv, every project shares one set of package versions, so upgrading a library for one project silently breaks another, and your system Python slowly becomes a tangled, irreproducible mess. A venv flips the model: each project gets its own isolated box of exactly the packages and versions *it* needs, so projects cannot interfere, you can pin and reproduce dependencies through `requirements.txt`, and you never pollute the system Python that the OS itself may depend on. The single rule that prevents about 90% of Python environment pain: never `pip install` into the global Python — always create and activate a venv first, one per project. Isolation is not an advanced technique. It is the correct default.
How do you deactivate and clean up a virtual environment?
When you are done working, leave the environment with one command (no path, no OS-specific variant):
“`bash deactivate “`
Your prompt loses the `(venv)` prefix and `python`/`pip` go back to the system defaults. The environment still exists on disk; you just stepped out of it. Activate it again whenever you return to the project.
Because the `.venv` folder is local and disposable, you do not commit it to Git. It is large, machine-specific, and fully rebuildable from `requirements.txt`. Add it to `.gitignore`:
“`gitignore
.venv/ venv/ __pycache__/ *.pyc “`
What you *do* commit is `requirements.txt`. What you delete and rebuild freely is the environment folder:
“`bash
rm -rf .venv python -m venv .venv source .venv/bin/activate pip install -r requirements.txt “`
If an environment ever gets into a weird state, deleting and rebuilding it is faster and safer than debugging it.
venv vs virtualenv vs conda: which should you use?
Three tools come up constantly. Short version: for most projects, the built-in `venv` is the right answer.
| Tool | What it is | When to use it |
|---|---|---|
| venv | Built into the standard library (Python 3.3+); no install needed | The default for almost every project. Start here. |
| virtualenv | Older third-party tool; faster and supports older Pythons | Legacy projects, or when you need features `venv` lacks. |
| conda | Separate package + environment manager from the data-science world | Heavy scientific stacks where non-Python binaries (CUDA, MKL) matter. |
`virtualenv` predates `venv` and inspired it; `venv` is essentially a slimmed-down, built-in subset. `conda` is a different ecosystem entirely — it manages non-Python dependencies too, which is why data scientists like it, but it is overkill for a typical web app. If you are not sure, use `venv`.
What is the per-project virtual environment workflow?
Put the whole thing together. This is the rhythm for every new project — internalize it once and it becomes muscle memory:
“`bash
mkdir my-app && cd my-app
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install flask
pip freeze > requirements.txt
deactivate “`
One venv per project. Do not share a single environment across multiple projects — that recreates the global-install problem with extra steps. The folder is cheap; isolation is the point.
For a teammate cloning the repo, the onboarding is just steps 2, 3, and `pip install -r requirements.txt`. If you are still setting up the interpreter itself, see how to and before creating the environment.
How do you use virtual environments on a server?
Everything above applies identically on a deployment server — and this is where isolation stops being a convenience and becomes a requirement. A server typically runs more than one app, and its operating system depends on the system Python. You do not want a deploy step quietly upgrading a library the OS needs.
On the server, the pattern is the same `venv` workflow, run once during deploy:
“`bash
python3 -m venv .venv source .venv/bin/activate pip install -r requirements.txt
.venv/bin/gunicorn app:app –bind 0.0.0.0:8000 “`
A process manager (systemd, supervisor) then points directly at the venv’s interpreter so the app always uses its isolated dependencies, regardless of what the shell environment looks like:
“`ini
[Service] WorkingDirectory=/srv/my-app ExecStart=/srv/my-app/.venv/bin/gunicorn app:app –bind 127.0.0.1:8000 “`
The catch: this only works cleanly when you control the environment. Locked-down shared hosting often pins one Python version, blocks `pip`, or denies the filesystem and process control that a deployed Python app needs. To run `venv` the right way in production you want full control over the runtime — exactly what a complete developer hosting environment is supposed to give you. If you are weighing where to run it, compare your options for before you commit.
Deploy Python the way it is meant to be deployed with DarazHost. DarazHost VPS and dedicated servers give developers full control to run Python apps the right way — create per-project virtual environments, pin dependencies, and deploy isolated, reproducible apps with full root access and any Python version you choose, never fighting a shared system Python. It is the controllable environment that real Python deployment needs, backed by 24/7 support.
How do you manage packages inside the environment?
Day-to-day package work all happens with the venv active. A few commands beyond `install` round out the workflow:
“`bash
pip install –upgrade requests
pip uninstall requests
python -m pip install –upgrade pip
pip list –outdated “`
After any install or uninstall, re-freeze so `requirements.txt` stays the source of truth:
“`bash pip freeze > requirements.txt “`
For deeper coverage of dependency management and resolving version conflicts, see the dedicated .
Quick reference: venv commands
| Command | What it does |
|---|---|
| `python -m venv .venv` | Create a new virtual environment in `.venv` |
| `source .venv/bin/activate` | Activate it (Mac/Linux) |
| `.venv\Scripts\activate` | Activate it (Windows) |
| `which python` | Confirm the active interpreter is the venv’s |
| `pip install |
Install a package into the active environment |
| `pip freeze > requirements.txt` | Pin exact installed versions to a file |
| `pip install -r requirements.txt` | Rebuild the environment from the pinned file |
| `pip list` | List packages installed in the environment |
| `deactivate` | Exit the environment, back to system Python |
Frequently asked questions
Do I need to install anything to use `python -m venv`? No. The `venv` module ships with Python 3.3 and later as part of the standard library. As long as you have a modern Python installed, `python -m venv` works out of the box. (On some Debian/Ubuntu systems you may need the `python3-venv` package, which is the only common exception.)
Should I name the folder `venv` or `.venv`? Either works. `.venv` is increasingly the convention because the dot prefix hides it and many editors auto-detect it. Pick one and stay consistent across your projects.
Do I commit the virtual environment folder to Git? No. The environment is local, large, and machine-specific. Add `.venv/` to `.gitignore` and commit `requirements.txt` instead — that file lets anyone rebuild the exact environment.
Can I have more than one virtual environment active at once? No, and you should not try. Activate one environment per shell session for one project. If you switch projects, `deactivate` the first and activate the second. One venv per project is the rule.
What is the difference between `venv` and `virtualenv`? `venv` is built into Python’s standard library and is the recommended default. `virtualenv` is an older third-party tool that is faster and supports older Python versions. For new projects on modern Python, use the built-in `venv`.