|
| 1 | +# Environment sources |
| 2 | + |
| 3 | +----- |
| 4 | + |
| 5 | +The `sources` table of an environment redirects dependencies to alternative origins at install time without changing your project's published metadata. This is useful during development when you want to consume a dependency from a local checkout, a Git branch, a private index, or another workspace member, while keeping the released wheel pointing at the version you ship. |
| 6 | + |
| 7 | +A source is matched against your dependencies by name, after [PEP 503 normalization](https://peps.python.org/pep-0503/#normalized-names). Both [project dependencies](../metadata.md#dependencies) and [environment dependencies](overview.md#dependencies) are eligible for redirection. |
| 8 | + |
| 9 | +```toml config-example |
| 10 | +[project] |
| 11 | +dependencies = ["foo"] |
| 12 | + |
| 13 | +[tool.hatch.envs.default.sources] |
| 14 | +foo = "./packages/foo" |
| 15 | +``` |
| 16 | + |
| 17 | +The top-level `[tool.hatch.sources]` table is an alias for the `default` environment, so the following is equivalent: |
| 18 | + |
| 19 | +```toml config-example |
| 20 | +[tool.hatch.sources] |
| 21 | +foo = "./packages/foo" |
| 22 | +``` |
| 23 | + |
| 24 | +!!! note |
| 25 | + Sources only affect installs performed by Hatch when it manages an environment. They do not influence the metadata of wheels you build with `hatch build`. |
| 26 | + |
| 27 | +## Inheritance |
| 28 | + |
| 29 | +Sources follow the usual [inheritance](overview.md#inheritance) rules, merging entry by entry so that an environment can redirect a single dependency differently while every other entry it inherits stays in place: |
| 30 | + |
| 31 | +```toml config-example |
| 32 | +[tool.hatch.sources] |
| 33 | +foo = "./packages/foo" |
| 34 | +bar = "./packages/bar" |
| 35 | + |
| 36 | +[tool.hatch.envs.test-upstream.sources] |
| 37 | +foo = { git = "https://github.com/example/foo", branch = "main" } |
| 38 | +``` |
| 39 | + |
| 40 | +Here every environment installs both `foo` and `bar` from the local checkouts, except `test-upstream`, which keeps the local `bar` but tracks the upstream development branch of `foo`. |
| 41 | + |
| 42 | +An environment that does not inherit from `default`, such as a [detached](overview.md#detached-environments) one, receives no sources. |
| 43 | + |
| 44 | +## Path |
| 45 | + |
| 46 | +Use a relative or absolute path to a wheel, source distribution, or project directory: |
| 47 | + |
| 48 | +```toml config-example |
| 49 | +[tool.hatch.sources] |
| 50 | +foo = "./packages/foo" |
| 51 | +``` |
| 52 | + |
| 53 | +The shorthand above is equivalent to the full form: |
| 54 | + |
| 55 | +```toml config-example |
| 56 | +[tool.hatch.sources] |
| 57 | +foo = { path = "./packages/foo", editable = true } |
| 58 | +``` |
| 59 | + |
| 60 | +`editable` defaults to `true` to match Hatch's existing handling of local installs. Set `editable = false` for a non-editable install. If the package lives below the path root, set `subdirectory`: |
| 61 | + |
| 62 | +```toml config-example |
| 63 | +[tool.hatch.sources] |
| 64 | +foo = { path = "./monorepo", subdirectory = "packages/foo" } |
| 65 | +``` |
| 66 | + |
| 67 | +For editable installs the subdirectory is resolved into the path itself (equivalent to `path = "./monorepo/packages/foo"`), since installers expect a bare project directory. For non-editable installs the subdirectory is passed as a URL fragment, which also supports archives. |
| 68 | + |
| 69 | +## Git |
| 70 | + |
| 71 | +Pull from a Git repository: |
| 72 | + |
| 73 | +```toml config-example |
| 74 | +[tool.hatch.sources] |
| 75 | +foo = { git = "https://github.com/example/foo" } |
| 76 | +``` |
| 77 | + |
| 78 | +Pin to a specific revision with one of `rev`, `tag`, or `branch` (mutually exclusive): |
| 79 | + |
| 80 | +```toml config-example |
| 81 | +[tool.hatch.sources] |
| 82 | +foo = { git = "https://github.com/example/foo", rev = "abc1234" } |
| 83 | +bar = { git = "https://github.com/example/bar", tag = "v1.0" } |
| 84 | +baz = { git = "https://github.com/example/baz", branch = "main" } |
| 85 | +``` |
| 86 | + |
| 87 | +Use `subdirectory` when the Python package is not at the repository root. |
| 88 | + |
| 89 | +## URL |
| 90 | + |
| 91 | +Install a wheel or source archive from a URL: |
| 92 | + |
| 93 | +```toml config-example |
| 94 | +[tool.hatch.sources] |
| 95 | +foo = { url = "https://files.example.com/foo-1.0.tar.gz" } |
| 96 | +``` |
| 97 | + |
| 98 | +`subdirectory` is also supported for archives where the package is not at the root. |
| 99 | + |
| 100 | +## Index |
| 101 | + |
| 102 | +Resolve the dependency from a specific package index: |
| 103 | + |
| 104 | +```toml config-example |
| 105 | +[tool.hatch.sources] |
| 106 | +foo = { index = "https://pypi.example.com/simple" } |
| 107 | +``` |
| 108 | + |
| 109 | +The index URL is passed to the installer as `--extra-index-url`, so the default index (PyPI) remains the primary source. Multiple index sources are deduplicated and order-preserving. |
| 110 | + |
| 111 | +## Workspace |
| 112 | + |
| 113 | +Resolve the dependency from a [workspace](../../how-to/environment/workspace.md) member: |
| 114 | + |
| 115 | +```toml config-example |
| 116 | +[tool.hatch.sources] |
| 117 | +my-pkg = { workspace = true } |
| 118 | +``` |
| 119 | + |
| 120 | +The actual install path is determined by the matching member in `tool.hatch.envs.<ENV_NAME>.workspace.members`. This lets you declare workspace membership in one place and reference it from many environments. |
| 121 | + |
| 122 | +## Precedence |
| 123 | + |
| 124 | +A dependency that already uses a [PEP 508 direct reference](../dependency.md#direct-references) is left untouched — the explicit URL on the dependency wins over a configured source. |
| 125 | + |
| 126 | +## Disabling sources |
| 127 | + |
| 128 | +Setting the `HATCH_NO_SOURCES` environment variable to any non-empty value disables all sources. This is useful in CI to verify that your published metadata resolves on its own, without local redirections: |
| 129 | + |
| 130 | +``` |
| 131 | +HATCH_NO_SOURCES=1 hatch env create |
| 132 | +``` |
| 133 | + |
| 134 | +## Inspecting sources |
| 135 | + |
| 136 | +The [`dep show sources`](../../cli/reference.md#hatch-dep-show) command displays each configured source, its target, and the dependencies of the active environment that it redirects. Sources that match no dependencies are reported with a warning, which helps catch typos in source names since unmatched sources are otherwise silently ignored. |
| 137 | + |
| 138 | +## Installer translation |
| 139 | + |
| 140 | +Sources produce installer-agnostic instructions that Hatch renders into the right flags for the configured installer: |
| 141 | + |
| 142 | +| Source | Per-dependency form | Global flags | |
| 143 | +| --- | --- | --- | |
| 144 | +| `path` (editable) | `--editable <resolved>` | none | |
| 145 | +| `path` (non-editable) | `name @ file://<resolved>` | none | |
| 146 | +| `git` | `name @ git+<url>[@<ref>]` | none | |
| 147 | +| `url` | `name @ <url>` | none | |
| 148 | +| `index` | unchanged | `--extra-index-url <url>` | |
| 149 | +| `workspace` | resolved through `workspace.members` | none | |
| 150 | + |
| 151 | +Both [`installer = "pip"`](overview.md#dependencies) and `installer = "uv"` accept the same flag forms, so the same source configuration works for either. When an environment is [`locked`](overview.md#locked), sources also apply during lock resolution: rewritten requirements flow into the lock inputs and index sources are passed to the resolver as `--extra-index-url`. |
| 152 | + |
| 153 | +!!! note |
| 154 | + Sources do not apply to [build requirements](../build.md#build-system) (`build-system.requires` or build target dependencies). Build environments always resolve from declared metadata so that builds remain reproducible. |
0 commit comments