How NuGet Works
Tags: dotnet, nuget
Published: 2020-06-07 19:51:11

Ever wondered how package managers work?

[NuGet](https://docs.microsoft.com/en-us/nuget/what-is-nuget) is the package manager for the .NET ecosystem that has served billions of downloads worldwide. Let's take a look under the hood and see what happens when you install a package on Visual Studio.

# Table of contents

* [Package Source](#package-source)
* [Discover packages](#discover-packages)
* [Inspect package details](#inspect-package-details)
* [Install packages](#install-packages)
* [Conclusion](#conclusion)

# Package Source

If you open Visual Studio's options, you'll see the following under the `Package Sources` section:

![Visual Studio package sources](https://dev-to-uploads.s3.amazonaws.com/i/x21zcf6gv2a7040sclid.png)

Visual Studio uses this package source to discover and download packages. The default source is [nuget.org](https://www.nuget.org/), which has the following package source URL: [`https://api.nuget.org/v3/index.json`](https://api.nuget.org/v3/index.json).

If you open that URL in your browser, you'll see:

```json
{
  "version": "3.0.0",
  "resources": [
    {
      "@id": "https://azuresearch-usnc.nuget.org/query",
      "@type": "SearchQueryService",
      "comment": "Query endpoint of NuGet Search service (primary)"
    },
    ...
  ],
  ...
}
```

This is the [service index](https://docs.microsoft.com/en-us/nuget/api/service-index), which lists all the resources that the server supports. Each resource has the following properties:

* `@type` - Used to identify the resource
* `@id` - The resource's URL

For example, the [search resource](https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource) used to discover packages has the type `SearchQueryService` and can be found at the URL `https://azuresearch-usnc.nuget.org/query`.

> ⚠ Don't hard-code `azuresearch-usnc.nuget.org` in your app! NuGet servers can move their resources at any time - you should always discover resource URLs using the [service index](https://docs.microsoft.com/en-us/nuget/api/service-index).

# Discover packages

You can use Visual Studio's Package Manager UI to find packages:

![Visual Studio's package manager search](https://dev-to-uploads.s3.amazonaws.com/i/tjzd2coo7n64t9pynfin.gif)

This is powered by the source's [search resource](https://docs.microsoft.com/en-us/nuget/api/search-query-service-resource). If you search for `json`, this will trigger the following request: [`https://azuresearch-usnc.nuget.org/query?includePrerelease=true&semVerLevel=2.0.0&q=json`](`https://azuresearch-usnc.nuget.org/query?includePrerelease=true&semVerLevel=2.0.0&q=json`).

If you open that URL in your browser, you'll see:

```json
{
  ...
  "totalHits": 3818,
  "data": [
    {
      ...
      "id": "Newtonsoft.Json",
      "version": "12.0.3",
      "description": "Json.NET is a popular high-performance JSON",
      "totalDownloads": 506643420,
      ...
    },
    ...
  ]
}
```

This is the metadata for the latest version of each package relevant to `json`.

# Inspect package details

Now that you've discovered some packages, you can select one to view more details:

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/7l1vhute1qdkccrua19e.png)

This is powered by the [package metadata resource](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource). For example, you can find the package metadata for the package `Newtonsoft.Json` at this URL: [`https://api.nuget.org/v3/registration5-gz-semver2/newtonsoft.json/index.json`](https://api.nuget.org/v3/registration5-gz-semver2/newtonsoft.json/index.json)

If you open that URL in your browser, you'll see:

```json
{
  ...
  "items": [
    {
      "items": [
        {
          ...
          "catalogEntry": {
            "id": "Newtonsoft.Json",
            "version": "3.5.8",
            "description": "Json.NET is a popular high-performance JSON framework for .NET",
            "packageContent": "https://api.nuget.org/v3-flatcontainer/newtonsoft.json/3.5.8/newtonsoft.json.3.5.8.nupkg",
            ...
          },
          "packageContent": "https://api.nuget.org/v3-flatcontainer/newtonsoft.json/3.5.8/newtonsoft.json.3.5.8.nupkg",
        },
        ...
      ]
    }
  ],
  ...
}
```

This resource contains the metadata for *all* versions of `Newtonsoft.Json`.

# Install packages

If you press the `Install` button for the package `Microsoft.Extension.Logging`, this will kick off the following chain reaction:

1. Download the package
2. Inspect the package's dependencies
3. For each dependency, find the best version of that dependency to install and repeat steps 1-3

All of this is powered by the [package content resource](https://docs.microsoft.com/en-us/nuget/api/package-base-address-resource).

### Download the package

NuGet will download the package using this URL: [`http://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging/3.1.4/microsoft.extensions.logging.3.1.4.nupkg`](http://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging/3.1.4/microsoft.extensions.logging.3.1.4.nupkg)

### For each dependency, find the best version to install

A package can depend on other packages, and these dependencies can themselves have their own dependencies. As a result, NuGet needs to build a graph of all the dependencies using its [dependency resolution algorithm](https://docs.microsoft.com/en-us/nuget/concepts/dependency-resolution). To do this, NuGet needs to know the list of versions for each dependency.

For example, the package [`Microsoft.Extensions.Logging`](https://www.nuget.org/packages/Microsoft.Extensions.Logging) depends on [`Microsoft.Extensions.Logging.Abstractions`](https://www.nuget.org/packages/Microsoft.Extensions.Logging.Abstractions/), so NuGet will lookup versions here: [`https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging.abstractions/index.json`](https://api.nuget.org/v3-flatcontainer/microsoft.extensions.logging.abstractions/index.json).

If you open that in your browser, you'll see:

```json
{
  "versions": [
    "1.0.0-rc1-final",
    "1.0.0-rc2-final",
    ...
    "3.1.4"
  ]
}
```

These are all the versions of the `Microsoft.Extensions.Logging.Abstractions` package. NuGet will choose one of these to install.

> ⚠ The NuGet client could use the [package metadata resource](https://docs.microsoft.com/en-us/nuget/api/registration-base-url-resource) from the previous section to find packages' versions. However, performance is critical here! This endpoint returns just the right information to install the right package.

# Conclusion

Congratulations, you've learned how the NuGet protocol works! If you want even more information, I recommend the following resources:

* [NuGet's protocol documentation](https://docs.microsoft.com/en-us/nuget/api/overview) - This is the definitive guide on the NuGet API
* [NuGet's client SDK](https://docs.microsoft.com/en-us/nuget/reference/nuget-client-sdk) - Use this to write an app that interacts with NuGet servers

If you want to run your own NuGet server, check out my side project on GitHub! 😇

{% github loic-sharma/BaGet no-readme %}

In future posts, I'll deep dive into nuget.org's implementation of the NuGet protocol, so stay tuned! Feel free to comment if you have any feedback or questions!