diff --git a/crates/uv-cli/src/lib.rs b/crates/uv-cli/src/lib.rs
index b4b0a176a..56a4f0a88 100644
--- a/crates/uv-cli/src/lib.rs
+++ b/crates/uv-cli/src/lib.rs
@@ -779,6 +779,18 @@ fn parse_index_url(input: &str) -> Result, String> {
}
}
+/// Parse a string into an [`FlatIndexLocation`], mapping the empty string to `None`.
+fn parse_flat_index(input: &str) -> Result, String> {
+ if input.is_empty() {
+ Ok(Maybe::None)
+ } else {
+ match FlatIndexLocation::from_str(input) {
+ Ok(url) => Ok(Maybe::Some(url)),
+ Err(err) => Err(err.to_string()),
+ }
+ }
+}
+
/// Parse a string into an [`Url`], mapping the empty string to `None`.
fn parse_insecure_host(input: &str) -> Result, String> {
if input.is_empty() {
@@ -3730,8 +3742,15 @@ pub struct IndexArgs {
///
/// If a URL, the page must contain a flat list of links to package files adhering to the
/// formats described above.
- #[arg(long, short, help_heading = "Index options")]
- pub find_links: Option>,
+ #[arg(
+ long,
+ short,
+ env = "UV_FIND_LINKS",
+ value_delimiter = ' ',
+ value_parser = parse_flat_index,
+ help_heading = "Index options"
+ )]
+ pub find_links: Option>>,
/// Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those
/// provided via `--find-links`.
diff --git a/crates/uv-cli/src/options.rs b/crates/uv-cli/src/options.rs
index fb7cd5235..3fe5d0e77 100644
--- a/crates/uv-cli/src/options.rs
+++ b/crates/uv-cli/src/options.rs
@@ -194,14 +194,19 @@ impl From for PipOptions {
Self {
index_url: index_url.and_then(Maybe::into_option),
- extra_index_url: extra_index_url.map(|extra_index_urls| {
- extra_index_urls
+ extra_index_url: extra_index_url.map(|extra_index_url| {
+ extra_index_url
.into_iter()
.filter_map(Maybe::into_option)
.collect()
}),
no_index: if no_index { Some(true) } else { None },
- find_links,
+ find_links: find_links.map(|find_links| {
+ find_links
+ .into_iter()
+ .filter_map(Maybe::into_option)
+ .collect()
+ }),
..PipOptions::default()
}
}
@@ -243,8 +248,8 @@ pub fn resolver_options(
ResolverOptions {
index_url: index_args.index_url.and_then(Maybe::into_option),
- extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
- extra_index_urls
+ extra_index_url: index_args.extra_index_url.map(|extra_index_url| {
+ extra_index_url
.into_iter()
.filter_map(Maybe::into_option)
.collect()
@@ -254,7 +259,12 @@ pub fn resolver_options(
} else {
None
},
- find_links: index_args.find_links,
+ find_links: index_args.find_links.map(|find_links| {
+ find_links
+ .into_iter()
+ .filter_map(Maybe::into_option)
+ .collect()
+ }),
upgrade: flag(upgrade, no_upgrade),
upgrade_package: Some(upgrade_package),
index_strategy,
@@ -327,8 +337,8 @@ pub fn resolver_installer_options(
ResolverInstallerOptions {
index_url: index_args.index_url.and_then(Maybe::into_option),
- extra_index_url: index_args.extra_index_url.map(|extra_index_urls| {
- extra_index_urls
+ extra_index_url: index_args.extra_index_url.map(|extra_index_url| {
+ extra_index_url
.into_iter()
.filter_map(Maybe::into_option)
.collect()
@@ -338,7 +348,12 @@ pub fn resolver_installer_options(
} else {
None
},
- find_links: index_args.find_links,
+ find_links: index_args.find_links.map(|find_links| {
+ find_links
+ .into_iter()
+ .filter_map(Maybe::into_option)
+ .collect()
+ }),
upgrade: flag(upgrade, no_upgrade),
upgrade_package: if upgrade_package.is_empty() {
None
diff --git a/crates/uv/tests/pip_compile.rs b/crates/uv/tests/pip_compile.rs
index 2638aa3dd..c8bc765b8 100644
--- a/crates/uv/tests/pip_compile.rs
+++ b/crates/uv/tests/pip_compile.rs
@@ -4593,6 +4593,33 @@ fn find_links_requirements_txt() -> Result<()> {
Ok(())
}
+/// Compile using the `UV_FIND_LINKS` environment variable
+#[test]
+fn find_links_uv_env_var() -> Result<()> {
+ let context = TestContext::new("3.12");
+ let requirements_in = context.temp_dir.child("requirements.in");
+ requirements_in.write_str("tqdm")?;
+
+ uv_snapshot!(context.filters(), context.pip_compile()
+ .arg("requirements.in")
+ .arg("--no-index")
+ .env("UV_FIND_LINKS", "https://download.pytorch.org/whl/torch_stable.html"), @r###"
+ success: true
+ exit_code: 0
+ ----- stdout -----
+ # This file was autogenerated by uv via the following command:
+ # uv pip compile --cache-dir [CACHE_DIR] requirements.in --no-index
+ tqdm==4.64.1
+ # via -r requirements.in
+
+ ----- stderr -----
+ Resolved 1 package in [TIME]
+ "###
+ );
+
+ Ok(())
+}
+
/// `extras==0.0.2` fails to build (i.e., it always throws). Since `extras==0.0.1` is pinned, we
/// should never even attempt to build `extras==0.0.2`, despite an unpinned `extras[dev]`
/// requirement.
diff --git a/docs/configuration/environment.md b/docs/configuration/environment.md
index 917ebd164..cf29ad291 100644
--- a/docs/configuration/environment.md
+++ b/docs/configuration/environment.md
@@ -6,6 +6,8 @@ uv accepts the following command-line arguments as environment variables:
URL as the base index for searching for packages.
- `UV_EXTRA_INDEX_URL`: Equivalent to the `--extra-index-url` command-line argument. If set, uv will
use this space-separated list of URLs as additional indexes when searching for packages.
+- `UV_FIND_LINKS`: Equivalent to the `--find-links` command-line argument. If set, uv will use this
+ space-separated list of additional locations to search for packages.
- `UV_CACHE_DIR`: Equivalent to the `--cache-dir` command-line argument. If set, uv will use this
directory for caching instead of the default cache directory.
- `UV_NO_CACHE`: Equivalent to the `--no-cache` command-line argument. If set, uv will not use the
diff --git a/docs/reference/cli.md b/docs/reference/cli.md
index 83292120a..34a03105b 100644
--- a/docs/reference/cli.md
+++ b/docs/reference/cli.md
@@ -148,6 +148,7 @@ uv run [OPTIONS]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--frozenRun without updating the uv.lock file.
Instead of checking if the lockfile is up-to-date, uses the versions in the lockfile as the source of truth. If the lockfile is missing, uv will exit with an error. If the pyproject.toml includes changes to dependencies that have not been included in the lockfile yet, they will not be present in the environment.
@@ -692,6 +693,7 @@ uv add [OPTIONS] >
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--frozenAdd dependencies without re-locking the project.
The project environment will not be synced.
@@ -1009,6 +1011,7 @@ uv remove [OPTIONS] ...
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--frozenRemove dependencies without re-locking the project.
The project environment will not be synced.
@@ -1314,6 +1317,7 @@ uv sync [OPTIONS]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--frozenSync without updating the uv.lock file.
Instead of checking if the lockfile is up-to-date, uses the versions in the lockfile as the source of truth. If the lockfile is missing, uv will exit with an error. If the pyproject.toml includes changes to dependencies that have not been included in the lockfile yet, they will not be present in the environment.
@@ -1617,6 +1621,7 @@ uv lock [OPTIONS]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--frozenAssert that a uv.lock exists, without updating it
--help, -hDisplay the concise help for this command
@@ -1896,6 +1901,7 @@ uv export [OPTIONS]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--format formatThe format to which uv.lock should be exported.
At present, only requirements-txt is supported.
@@ -2204,6 +2210,7 @@ uv tree [OPTIONS]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--frozenDisplay the requirements without locking the project.
If the lockfile is missing, uv will exit with an error.
@@ -2575,6 +2582,7 @@ uv tool run [OPTIONS] [COMMAND]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--from fromUse the given package to provide the command.
By default, the package name is assumed to match the command name.
@@ -2863,6 +2871,7 @@ uv tool install [OPTIONS]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--forceForce installation of the tool.
Will replace any existing entry points with the same name in the executable directory.
@@ -3147,6 +3156,7 @@ uv tool upgrade [OPTIONS] ...
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--help, -hDisplay the concise help for this command
--index-strategy index-strategyThe strategy to use when resolving against multiple index URLs.
@@ -4711,6 +4721,7 @@ uv pip compile [OPTIONS] ...
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--generate-hashesInclude distribution hashes in the output file
--help, -hDisplay the concise help for this command
@@ -5099,6 +5110,7 @@ uv pip sync [OPTIONS] ...
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--help, -hDisplay the concise help for this command
--index-strategy index-strategyThe strategy to use when resolving against multiple index URLs.
@@ -5441,6 +5453,7 @@ uv pip install [OPTIONS] |--editable If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--help, -hDisplay the concise help for this command
--index-strategy index-strategyThe strategy to use when resolving against multiple index URLs.
@@ -6610,6 +6623,7 @@ uv venv [OPTIONS] [PATH]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--help, -hDisplay the concise help for this command
--index-strategy index-strategyThe strategy to use when resolving against multiple index URLs.
@@ -6857,6 +6871,7 @@ uv build [OPTIONS] [SRC]
If a URL, the page must contain a flat list of links to package files adhering to the formats described above.
+May also be set with the UV_FIND_LINKS environment variable.
--help, -hDisplay the concise help for this command
--index-strategy index-strategyThe strategy to use when resolving against multiple index URLs.