You can install Python packages from a local source directory using pip without needing to upload them to PyPI or a private repository.

Here’s a package structure you might have locally:

/path/to/your/local/packages/
├── my_package_a/
│   ├── my_package_a/
│   │   ├── __init__.py
│   │   └── module.py
│   └── pyproject.toml
└── my_package_b/
    ├── my_package_b/
    │   ├── __init__.py
    │   └── another_module.py
    └── setup.py

To install my_package_a and my_package_b into your current Python environment, you’d run:

pip install /path/to/your/local/packages/my_package_a
pip install /path/to/your/local/packages/my_package_b

If you have both packages in the same directory, pip can often infer them:

pip install /path/to/your/local/packages/

This command will look for discoverable packages within /path/to/your/local/packages/. A "discoverable" package is typically one that contains a pyproject.toml or setup.py file at its root.

Let’s break down how this works and what you control. pip’s primary job is to find and install Python packages. When you provide a local directory path, pip treats that directory as a source of packages. It scans this directory for subdirectories that appear to be Python packages. The presence of a pyproject.toml (the modern standard) or setup.py (the older standard) is the key signal pip uses to identify these package roots. Once identified, pip will build and install these packages just as if they were downloaded from an index.

You can also specify a particular package file if you have one, like a wheel (.whl) or a source distribution (.tar.gz, .zip).

pip install /path/to/your/local/packages/my_package_a-1.0.0-py3-none-any.whl
pip install /path/to/your/local/packages/my_package_b-0.5.0.tar.gz

This is useful if you’ve built the package artifacts and want to distribute them directly. pip knows how to unpack and install these formats.

Dependencies are handled automatically. If my_package_a declares a dependency on requests in its pyproject.toml or setup.py, and requests is not already installed in your environment, pip will attempt to find and install requests from your configured package indexes (like PyPI). If you want to install local dependencies too, you can simply list them all:

pip install /path/to/your/local/packages/my_package_a /path/to/your/local/packages/my_dependency_package

Or, if they are all in one directory:

pip install /path/to/your/local/packages/

pip will process all discoverable packages in the specified directory and resolve their dependencies, installing them in the correct order.

The -e or --editable flag is a powerful option here. If you use pip install -e /path/to/your/local/packages/my_package_a, pip will install the package in "editable" mode. This means instead of copying the package files into your site-packages directory, it creates a link to your source code directory. Any changes you make to your source code will be immediately reflected in the installed package without needing to reinstall. This is incredibly useful during development.

pip install -e /path/to/your/local/packages/my_package_a

When pip install -e is used on a directory containing multiple packages, it installs all discoverable packages in that directory in editable mode.

pip install -e /path/to/your/local/packages/

This command makes my_package_a and my_package_b editable in your environment.

The pip install command essentially runs python setup.py install (for older setup.py based packages) or build and then installs the result (for pyproject.toml based packages), but it does so in a way that integrates with your environment’s package management. When installing from a local source, pip uses the build backend specified in pyproject.toml or the instructions in setup.py to create a package distribution (like a wheel) in a temporary location, and then installs that distribution. The editable install bypasses the temporary build step, directly linking your active Python environment’s site-packages to your source code.

A common pitfall is when pip doesn’t find your package in a local directory. This usually means the directory structure isn’t quite right, or the pyproject.toml or setup.py is missing or malformed. pip expects to find these files at the root of the package’s source directory, not nested deep within subdirectories that aren’t themselves package roots. For example, if your structure is /path/to/your/local/packages/my_package_a/src/my_package_a/, pip install /path/to/your/local/packages/my_package_a will likely not find my_package_a unless the pyproject.toml or setup.py is also in /path/to/your/local/packages/my_package_a/. The convention is often to have the pyproject.toml or setup.py at the top level of the package’s repository, alongside a src/ directory containing the actual package code.

If you need to install a local package and its dependencies from other local paths, you can use the --find-links or -f option, pointing to a directory containing the wheels or source distributions of your dependencies.

pip install --find-links=/path/to/local/dependency/repo my_package_a

This tells pip to look in /path/to/local/dependency/repo for any dependencies required by my_package_a before checking PyPI.

Want structured learning?

Take the full Pip course →