Demystifying Frappe's Dual Virtual Environments


When setting up a Frappe or ERPNext development environment, many developers start by creating a Python virtual environment to isolate dependencies. Inside that environment, we usually install Bench, which then helps us create and manage Frappe sites and apps.

However, what often goes unnoticed is that Frappe itself creates another virtual environment inside your bench directory.

This internal environment — located at:
frappe-bench/env/— is where Frappe and all its required Python packages 📦 actually live and run.
Let’s break this down clearly:
python3 -m venv venv or conda create ...).bench start, bench new-site, etc. bench init frappe-bench).frappe, redis, gunicorn, pymysql, etc. are installed here. So when you’re running your Frappe apps, the Python interpreter that executes your code is not the outer environment — it’s the one under frappe-bench/env.
pip install Might Not Work as Expected ❌A common source of confusion arises when developers install additional packages like this:
pip install requestsThis command installs the package in your outer environment — the one where Bench was installed. But Frappe doesn’t use that environment when executing your apps.
That means when you later try to import your newly installed package from within a Frappe app, you might see an error like:
ModuleNotFoundError: No module named 'requests'Even though you “installed” it, Frappe can’t find it — because it’s not in its own virtual environment.
bench pip ✅To make sure packages are installed inside Frappe’s internal environment, always run:
bench pip install <package_name>For example:
bench pip install requestsThis ensures the package is installed inside frappe-bench/env, making it accessible to all your Frappe apps.
You can also use other familiar pip commands in the same way:
bench pip list
bench pip uninstall <package_name>
bench pip freezeThese commands behave exactly like normal pip, but target the Frappe environment managed by Bench.
You can verify the path of your active Python environment by running:
bench exec which pythonor
bench console
>>> import sys
>>> print(sys.executable)You’ll notice the path points to something like:
/home/username/frappe-bench/env/bin/pythonThat’s the interpreter where Frappe and all your bench-managed apps run.
| Task | Wrong Way ❌ (Installs in Outer Env) | Correct Way ✅ (Installs in Frappe Env) |
|---|---|---|
| Install a Python package | pip install requests | bench pip install requests |
| List installed packages | pip list | bench pip list |
| Uninstall a package | pip uninstall requests | bench pip uninstall requests |
By understanding this simple but crucial distinction, you’ll avoid a lot of “module not found” errors and keep your Frappe environment clean and consistent.
If you ever need to manage dependencies across multiple benches, each bench has its own isolated environment under its folder. So, bench pip install commands apply per bench, not system-wide.

Stop fighting Git permissions in WSL. This post explains the root cause of the 'Permission Denied' error and shows you the permanent fix.

Learn why the Frappe framework's built-in reporting is a game-changer. See how to customize, group, and save reports instantly

Learn how to use Frappe's Assignment Rule DocType to automate document assignments. Explore Round Robin, Load Balancing, and custom Python rules.