Including Private Feed NuGet packages in an Azure DevOps Internal NuGet Feed
As part of a larger push to make developers life simpler, I was recently asked to include some external libraries used by various teams in the organization’s local Azure DevOps NuGet Feed. This exercise was meant to help to secure credentials (every dev shouldn’t need to add the source locally, which requires username/password), as well as help centralize the places from which libraries are shared. While this is a relatively straightforward task, I did have to piece together how to do this, so I thought I would post it here to simplify any one else’s future efforts.
Service Connection Setup
The first task at hand is to ensure that there is a Service Connection between the DevOps instance and the NuGet feed. You will first need to navigate to the Service connections tab. This is done by clicking “Project Settings” then finding “Service connections” under the Pipelines section.

Next, you will need to create a new service connection. Choose NuGet as the type of connection. After clicking “Next” you can then fill out the information for connecting to the NuGet feed.


Setup NuGet Config
Now that we have a connection set up, we need to create a small project that will restore the packages. The first item needed is a nuget.config, used to help identify the sources required during package restoration. This just provides all of the available feeds. I place this file in a folder called nuget, so the following code is under /nuget/myfeed-nuget.config.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<!-- Package sources -->
<packageSources>
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
<!-- Private feed -->
<add key="MyExternalFeed" value="https://nuget.external-feed.dev/nuget/v3/index.json" />
</packageSources>
</configuration>
Package Restoration
After setting up our local sources, we will need a way to restore the packages that we want to consume. The easiest way to do this is via package restoration with dotnet. I created a simple csproj file that indicates all packages I want to restore, and place it in a packages folder. This file would be located at /packages/myfeed-packages.csproj.
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net9.0;net8.0;</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Feed.Package.First" Version="[3.0.0,)" />
<PackageReference Include="Feed.Package.Second" Version="2.0.4" />
<PackageReference Include="Feed.Package.Third" Version="3.3.1" />
<PackageReference Include="Feed.Package.Fourth" Version="[3.3.1,)" />
</ItemGroup>
</Project>
Pipeline Set Up
Now that we have our project all set up, we need to create the pipeline that will execute the action to restore the packages, then push them to the NuGet Feed. You have the option to either create a new pipeline yaml and selecting the file as existing during setup, or updating the starter pipeline yaml that is provided.

The following example pipeline yaml runs nightly to update the feed. It is located in the .azure-pipelines folder.
trigger: none
schedules:
- cron: "0 3 * * *"
displayName: "Nightly Run"
branches:
include:
- main
always: true
pool:
vmImage: windows-latest
variables:
AZURE_FEED: #FEED GUID GOES HERE IN SINGLE QUOTES
steps:
- script: echo Starting Feed Restore
displayName: 'Restore Start'
#restore packages
- task: NuGetCommand@2
inputs:
command: 'restore'
restoreSolution: 'packages/myfeed-packages.csproj'
feedsToUse: 'config'
nugetConfigPath: 'nuget/myfeed-nuget.config'
externalFeedCredentials: 'My New Connection' #Service Connection Name
noCache: true
restoreDirectory: '$(Pipeline.Workspace)/myfeed-packages/'
#Push to internal feed
- task: NuGetCommand@2
displayName: Push packages to Azure Artifacts
inputs:
command: push
packagesToPush: '$(Pipeline.Workspace)/myfeed-packages/**/*Feed.Package*.nupkg'
nuGetFeedType: internal
publishVstsFeed: '$(AZURE_FEED)'
allowPackageConflicts: true
Pipeline Permissions
Now that the pipeline is set up, you must ensure that it has permissions to use the connection. Navigate back to the Service Connections page, and select the newly created connection. Next to the edit button, there is an option to edit security, click on this.

Under Security, you can choose your new pipeline from the pipeline permissions options. Once you have granted access, you can run your pipeline to test that everything is working properly. After testing, come back and verify that the pipeline is running as scheduled with no issues, and your NuGet feed will be kept up to date with your external libraries.

Conclusion
Adding the external libraries to your internal NuGet feed is a simple task that allows developers to easily access required libraries when adding features. Using these simple steps is a small way to help increase productivity and keep external credentials secure. I have provided sample files for this project in my GitHub to help others get a quick start.
