Editable Installs & Local Packages
Editable installs link your source tree into the virtual environment so code changes take effect immediately. Combined with src/ layout, this gives reliable imports in development and tests.
Recipe
# src/ layout project
uv pip install -e .
# or: pip install -e .
# Local path dependency in pyproject.toml
# dependencies = ["my-utils @ file:///path/to/my-utils"]When to reach for this:
- Active development on a library or application package
- Monorepos with interdependent local packages
- Tests that must import the installed package, not the repo root
Working Example
myapp/
├── pyproject.toml
├── src/
│ └── myapp/
│ ├── __init__.py
│ └── core.py
└── tests/
└── test_core.py
[project]
name = "myapp"
version = "0.1.0"
requires-python = ">=3.14"
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[tool.hatch.build.targets.wheel]
packages = ["src/myapp"]uv pip install -e ".[dev]"
uv run pytest# tests/test_core.py
from myapp.core import greet
def test_greet():
assert greet("Ada") == "Hello, Ada!"What this demonstrates:
src/layout prevents accidental imports from the repo root- Editable install makes
import myappresolve tosrc/myapp/ - Tests exercise the same import path production uses
- Changes to
core.pyare visible on next test run without reinstall
Deep Dive
How It Works
pip install -e .writes a.pthfile in the venv pointing tosrc/- The build backend discovers packages via
pyproject.tomlconfig - Path dependencies (
my-utils @ file://...) symlink local packages into the dependency tree - uv workspaces coordinate multiple editable packages in a monorepo
src Layout vs Flat Layout
| Layout | Import risk | Recommended |
|---|---|---|
src/myapp/ | Low (must install) | Yes |
myapp/ at root | Tests import uninstalled code | No |
Python Notes
# uv workspace for monorepos
[tool.uv.workspace]
members = ["packages/*"]
# packages/myapp/pyproject.toml
[project]
name = "myapp"
dependencies = ["my-utils"]
# packages/my-utils/pyproject.toml
[project]
name = "my-utils"uv sync # installs all workspace members editableGotchas
- Tests pass without install (flat layout) - CI fails because the package was never built. Fix: adopt
src/layout; alwayspip install -e .before testing. - Editable install after renaming package - stale
.pthpoints to old path. Fix: reinstall:uv pip install -e . --force-reinstall. - Absolute path deps in pyproject.toml - breaks on other machines. Fix: use uv workspaces or relative path deps for monorepos.
- Missing
__init__.py- namespace packages may confuse editable discovery. Fix: include__init__.pyunless you intentionally use namespace packages. - Publishing an editable-only package -
pip installfrom PyPI needs a real wheel. Fix: editable is for dev;uv buildfor distribution.
Alternatives
| Alternative | Use When | Don't Use When |
|---|---|---|
PYTHONPATH=src | Quick hack, no install | Production or CI (fragile) |
Regular install (pip install .) | Verifying the built package | Active development |
| uv workspace | Monorepo with 2+ packages | Single-package apps |
FAQs
What does -e stand for?
Editable. The installed package links back to your source directory.
Do I need to reinstall after adding a new module?
No for new .py files inside an existing package. Yes if you add a new top-level package or change entry points.
Why use src/ layout?
It forces tests to import the installed package, catching packaging bugs before release.
How do monorepo path deps work?
uv workspaces or dependencies = ["sibling @ file:///${PROJECT_ROOT}/packages/sibling"] with relative paths.
Can I editable-install a dependency?
Yes: uv pip install -e ../my-utils or declare it as a workspace member.
Does editable work with Poetry?
Yes: poetry install installs the current project editable by default.
What about data files in editable mode?
Package data must be declared in pyproject.toml ([tool.hatch.build.targets.wheel.force-include]). Source edits to data files are picked up immediately.
How do I verify the install path?
python -c "import myapp; print(myapp.__file__)" should point to src/myapp/.
Editable in Docker?
Mount source as a volume and pip install -e . in the container for live-reload development.
Can I mix editable and regular deps?
Yes. Only your project (and workspace siblings) are editable; PyPI deps install normally.
Related
- pyproject.toml Explained - package config
- uv - The Fast Toolchain - workspace support
- Packaging Basics - wheels and sdists
- Environments Best Practices - layout conventions
Stack versions: This page was written for Python 3.14.0, FastAPI 0.115+, Django 5.2, Flask 3.1, Pydantic 2, PyTorch 2.6+, pandas 2.2+, Polars 1.x, ruff 0.9+, and uv 0.6+.