NuGet feed

A read-only NuGet v3 feed backed by one or more folders of nupkgs.


SharpDocs exposes a NuGet v3 feed at /v3/index.json. It implements the subset of v3 needed for dotnet restore to work against a folder of nupkgs.

What gets indexed

  • Every *.nupkg directly under each configured artifacts folder is opened as a zip.
  • The root .nuspec is parsed (id, version, description, authors, tags, dependencies).
  • Files ending in .symbols.nupkg are skipped.
  • Packages are grouped by id; versions are sorted ascending so the last entry is "latest".

In single-project mode there is one artifacts folder, configured via SharpDocs:ArtifactsRoot. In multi-project mode there are N folders — one per project, declared in each project's sharpdocs.json. They merge into one feed; (id, version) collisions across folders are resolved first-wins by project order.

There is no caching layer between the feed and disk. Restart the host to pick up new packages.

Endpoints

Route Purpose
GET /v3/index.json Service index
GET /v3/flatcontainer/{id}/index.json Version list
GET /v3/flatcontainer/{id}/{version}/{id}.{version}.nupkg Download the nupkg
GET /v3/flatcontainer/{id}/{version}/{id}.nuspec Download the nuspec
GET /v3/registration/{id}/index.json Registration (metadata + deps)
GET /v3/search?q=&skip=&take=&prerelease= Search
GET /v3/autocomplete?q=&take= Id autocomplete

See Reference: NuGet v3 endpoints for the full shape.

Base URL

Absolute URLs in feed responses are derived from the incoming request (Scheme, Host, PathBase). The feed works unmodified behind a reverse proxy or on any host — no configuration needed.

See Host behind a reverse proxy for the forwarded-headers setup.

Consuming the feed

dotnet nuget add source https://your-site.example/v3/index.json --name my-feed
dotnet add package MyPackage

Browsing packages

/packages lists every id with its latest version, and /packages/{id} shows version history, dependencies, and a download link. In multi-project mode the listing is unified — every project's artifacts folder is merged into the same view, with no per-project filter. This UI is local-only — it does not enumerate upstream packages.

Composite mode (upstream feeds)

You can layer one or more upstream NuGet v3 feeds behind your own. Every /v3/* endpoint then merges local artifacts with live results from the upstreams. Clients see a single feed — yours — and never need to configure the upstreams directly.

builder.Services.AddSharpDocs(builder.Configuration)
    .AddUpstream("https://api.nuget.org/v3/index.json")
    .AddUpstream("https://other-feed.example/v3/index.json");

Upstreams can also come from appsettings.json:

"SharpDocs": {
  "Upstreams": [ { "Url": "https://api.nuget.org/v3/index.json" } ]
}

Behavior:

  • Version lists merge local + upstream versions, dedup, sort.
  • Registration responses merge leaves; every packageContent URL is rewritten to point back at your feed, so downloads always come through you.
  • Search and autocomplete fan out; local ids win on collision, then first upstream wins.
  • Downloads (.nupkg, .nuspec): if the local artifact exists, it's served from disk; otherwise the request is proxy-streamed from the first upstream that has the version. Bytes flow through your server — no 302 redirects, no on-disk cache.
  • Local always wins on id+version collisions.
  • A slow or failed upstream is logged and treated as empty — it never blocks the whole response.

Service-index URLs for each upstream are resolved once at startup (not per request). Upstream package data is fetched live on every request; there is no cache layer.

Tune the per-upstream HTTP timeout (default 10s) via:

"SharpDocs": {
  "UpstreamTimeoutSeconds": 5
}