Understanding pip's Editable Installs: When to Use -e and What Can Go Wrong
A practical look at pip's -e/--editable flag, showing how it works, a verification checklist, and the limits you should know before relying on it in production.
25 Aug 2026, 04:04 UTC

The problem: live code changes without reinstall
During development you often need to tweak a library that your project depends on. Re‑running pip install after every edit is slow and breaks the rapid feedback loop. Pip’s -e/--editable flag solves this by linking the source tree directly into the environment so that imports read the files you are editing.
How editable installs work
When you run pip install -e /path/to/pkg pip creates a lightweight reference to the source directory:
- On Unix‑like systems a symlink is placed in
site-packagespointing at the source. - On Windows a copy of the source tree (a “clone”) is made because symlinks require admin rights.
The package must be importable – it needs an __init__.py (or a pyproject.toml with a [build-system] that produces a proper module) and the directory must be on sys.path. Pip’s new resolver (default since pip 20.1) still performs full dependency resolution for the editable package, which can add a few seconds to the first install.
Worked example: installing a local package in editable mode
Assume you have a minimal package layout:
myproj/
├─ src/
│ └─ mylib/
│ ├─ __init__.py
│ └─ greet.py
└─ pyproject.toml
greet.py contains:
def hello():
return "Hello from mylib"
Install it in a virtual environment (no sudo required):
# create and activate venv
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
# editable install from the source root
pip install -e ./src
Verification steps (run in the same shell):
pip show -f mylib– theLocationline should point to/full/path/to/myproj/src, confirming editable mode.- Open a Python REPL and import:
from mylib.greet import hello; print(hello()). You should seeHello from mylib. - Edit
src/mylib/greet.pyand change the return string to"Hello from edited mylib". Re‑run the import in the same REPL (or start a new one) – the new text appears without anotherpip install. pip list --outdatedshould showmylibwith the same version, proving no accidental upgrade occurred.
Risk note: If you move, rename, or delete src/mylib the symlink/clone becomes dangling and imports will fail with ModuleNotFoundError.
Trade‑offs and limitations
| Aspect | Editable install | Regular (frozen) install |
|---|---|---|
| Source changes reflected instantly | Yes | No – requires reinstall |
| Reproducibility across machines | Poor – lockfiles (e.g., requirements.txt generated by pip freeze) omit the local path | Good – exact versions recorded |
| C extensions / compiled code | May fail if build tools (setuptools, Cython, a C compiler) aren’t present | Works if wheels are available |
| Moving the source directory | Breaks the install | Unaffected |
Because editable installs bypass the normal locking mechanism, they are unsuitable for production deployments or any environment that must be recreated identically. They also do not work reliably for packages that ship binary extensions unless the build toolchain is installed on the target machine.
Actionable closing checklist
- Use
pip install -eonly in development virtual environments. - Pin all *other* dependencies in a lockfile (e.g.,
pip-toolsorpip freeze > requirements.txt) so the rest of the environment stays reproducible. - If the package contains C extensions, ensure a compiler and the required build back‑ends are installed, or publish a wheel and install that instead.
- Before committing, run the verification steps above (
pip show -f, edit‑import test,pip list --outdated) to confirm the editable link is healthy. - When the feature is complete, switch to a regular install from a versioned wheel or sdist for CI/CD and production.
Following this pattern gives you the fast edit‑run cycle you need while keeping the rest of your dependency graph stable and auditable.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.