Skip to content

Commit f7c6093

Browse files
Introduce package downloading feature to dotnet (#14495)
1 parent 5fb1dc4 commit f7c6093

File tree

1 file changed

+154
-0
lines changed

1 file changed

+154
-0
lines changed
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Dotnet Package Download Command
2+
3+
* Author: [Nigusu](https://github.com/Nigusu-Allehu)
4+
* GitHub Issues: [#12513](https://github.com/NuGet/Home/issues/12513), [#14491](https://github.com/NuGet/Home/issues/14491)
5+
6+
## Summary
7+
8+
This document proposes adding a `dotnet package download` command to the .NET CLI.
9+
The command would enable package download to a local folder scenarios without requiring a project file.
10+
11+
## Motivation
12+
13+
Developers often need to download NuGet packages outside of a project context:
14+
15+
* Populating internal or offline feeds.
16+
* CI/CD workflows that consume `.nupkg` artifacts directly.
17+
* **Cross-platform builds** where many customers today rely on `nuget.exe install` in CI scripts running on Linux or macOS, forcing them to install Mono just to get this functionality.
18+
19+
Providing `dotnet package download` improves developer productivity, simplifies pipelines, and ensures a cross-platform experience within the .NET CLI.
20+
21+
## Explanation
22+
23+
### Command Overview
24+
25+
```ps1
26+
Description:
27+
Downloads a NuGet package to a local folder without requiring a project file.
28+
29+
Usage:
30+
dotnet package download <PackageId> [options]
31+
32+
Arguments:
33+
PackageId Package in the form of a package identifier (e.g. 'Newtonsoft.Json')
34+
or identifier and version separated by '@' (e.g. '[email protected]').
35+
36+
Options:
37+
-?, -h, --help Show command line help.
38+
--allow-insecure-connections Allows downloading from HTTP sources.
39+
--configfile <path> Path to a NuGet.config to use.
40+
--interactive Enables interactive authentication if required.
41+
-o, --output <path> Directory where the package will be placed. Defaults to the current working directory.
42+
--prerelease Allows downloading prerelease versions.
43+
-s --source <package source> Specifies the NuGet package source to use.
44+
-v --verbosity <level> Set the verbosity level of the command Allowed values are q[uiet], m[inimal], n[ormal], d[etailed], and diag[nostic].
45+
```
46+
47+
## Default Behavior
48+
49+
By default `dotnet package download` just like `nuget.exe install`:
50+
51+
* Download to the **current working directory** unless an output option (`--output`) is specified.
52+
* Select the **latest version** of a package if no version is provided.
53+
54+
However, they differ in a few key areas:
55+
56+
| **Aspect** | **`dotnet package download`** | **`nuget.exe install`** | Why different |
57+
| ------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------- |
58+
| **Dependency resolution** | Downloads **only the explicitly requested package** (no transitive dependencies). | Downloads the requested package **and all its dependencies** by default. | Current discussions in [NuGet/Home#12513](https://github.com/NuGet/Home/issues/12513) indicate no clear need for transitive dependency downloads. |
59+
| **Folder layout** | Creates a folder per **package ID**, with **version subfolders** (e.g., `Contoso/13.0.3/`). | Creates a folder per **package-version pair** (e.g., `Contoso.13.0.3/`). | The new layout allows multiple versions to coexist cleanly and aligns with the global packages folder structure. |
60+
61+
#### Example Layout
62+
63+
```ps1
64+
<output-directory>/
65+
Contoso/
66+
13.0.3/
67+
12.0.3/
68+
```
69+
70+
This layout allows multiple versions of the same package to coexist while remaining easy to locate: consistent with the **global packages folder** design used by modern .NET tools.
71+
72+
The design of dotnet package download was guided by feedback captured in [NuGet/Home#12513](https://github.com/NuGet/Home/issues/12513).
73+
Rather than replicating the full feature set of nuget.exe install, the new command intentionally focuses on simply addressing the specific needs of automation, CI/CD, and scripting scenarios.
74+
75+
### Version Resolution
76+
77+
Package versions are specified as part of the `PackageId` argument using the syntax `Package@Version`.
78+
You can specify one or more packages in a single command. For example, to download multiple packages:
79+
80+
```bash
81+
dotnet package download [email protected] [email protected]
82+
```
83+
84+
* **Package** — the name of the package.
85+
* **Version** — the exact version number to download.
86+
87+
Version ranges and floating versions are **not supported**.
88+
If no version is specified, the command downloads the **latest available version** from the configured sources.
89+
When the `--prerelease` option is enabled, pre-release versions are also included when determining the latest version.
90+
91+
### Audit
92+
93+
Audit functionality is **not supported** for the `dotnet package download` command by design.
94+
95+
* **No dependency graph** – The command downloads only explicitly requested packages and does not resolve transitive dependencies. Auditing is most meaningful when hidden or transitive dependencies are involved, which this command does not process
96+
* **Reliability in restricted environments** – For users that run this command in controlled or offline settings (for example, behind firewalls or without access to NuGet.org) avoiding network calls for vulnerability data ensures the command runs predictably without unexpected warnings or errors.
97+
* **Typical usage scenarios** – In CI/CD pipelines and automation systems, packages are often sourced from internal or validated feeds rather than NuGet.org, making external vulnerability checks less relevant.
98+
99+
### Source Selection and Package Source Mapping
100+
101+
The `dotnet package download` command supports both **explicit source selection** (`--source`) and **package source mapping** configured in `nuget.config`.
102+
103+
**Source precedence:**
104+
105+
1. **`--source` specified**
106+
107+
* When `--source <packageSource>` is provided, it **replaces** all sources defined in configuration files.
108+
* The value is first resolved as a **named source** from `nuget.config`; if no match is found, it is treated as a **direct URI**.
109+
* In this mode, **package source mapping is ignored**, and the command only uses the explicitly provided sources.
110+
111+
2. **No `--source` specified**
112+
113+
* When no `--source` is provided, the command reads all configured sources from the active `nuget.config`.
114+
* If **package source mapping** is enabled, the command uses the mapping rules to determine which source(s) to query for each package ID.
115+
* This ensures the correct source is chosen automatically based on patterns defined in the configuration file.
116+
117+
#### Exit Codes
118+
119+
The command follows standard exit code conventions:
120+
121+
* **0** – The package was successfully downloaded, or the requested version was already present.
122+
* **1** – The download failed, network errors, requested package version not found, parsing of the command arguments failed, all other errors during the command operation.
123+
124+
#### Supported options in nuget.exe install but not this command
125+
126+
The following options are currently supported in `nuget.exe install` but are not supported in the `dotnet package download` command.
127+
This decision is intentional — the initial implementation focuses on solving the key user scenarios outlined in [#12513](https://github.com/NuGet/Home/issues/12513).
128+
129+
Future iterations may introduce these options based on customer feedback and demand.
130+
Users are encouraged to share feedback if their workflows depend on any of these arguments.
131+
132+
* `-DependencyVersion`: Not applicable. This command never resolves transitive dependencies.
133+
* `-DirectDownload`
134+
* `-DisableParallelProcessing`
135+
* `-x | -ExcludeVersion`: Not applicable. Packages are stored in id/version/ structure; version-less folders do not apply.
136+
* `-FallbackSource`
137+
* `-ForceEnglishOutput`
138+
* `-Framework`
139+
* `-NoHttpCache`
140+
* `-PackageSaveMode`
141+
* `-RequireConsent`
142+
* `-SolutionDirectory`
143+
144+
For more information on these options, see the [`nuget.exe install` documentation](https://learn.microsoft.com/en-us/nuget/reference/cli-reference/cli-ref-install).
145+
146+
## Rationale and alternatives
147+
148+
* **Dummy projects**: Today, developers must create fake projects just to restore packages. This is cumbersome, error-prone, and requires extra cleanup.
149+
* **nuget.exe install**: Still widely used but Windows-centric and requires Mono on non-Windows platforms.
150+
151+
## Prior Art
152+
153+
* **`nuget.exe install`**: legacy but widely used.
154+
* The `Package@Version` is a design that is supported in dotnet commands like `package add`, `package update`.

0 commit comments

Comments
 (0)