Consuming, Building and Publishing private NuGet Pacakges to GitHub Packages with Azure DevOps Pipelines

If you are working on several closed-source projects and have many internal libraries that you wish to share as NuGet packages, you’d be looking for a way to privately host those packages. We had been using Azure DevOps Artifact Feed for this purpose. However, with the release of GitHub Packages we’ve started moving our packages there as all our devs were already on GitHub and we didn’t have to reprovision AzDO Package Management feature for those who weren’t really creating or maintaining build pipelines.

Following is what we did to keep our build pipelines in Azure DevOps and post the NuGet packages that they built in to GitHub Packages.


  • An Azure DevOps account
  • Access to Azure KeyValut
  • A GitHub account with GitHub Packages feature enabled

Prepare your project for GitHub Packages

When publishing the NuGet package you’ll be pushing from the pipeline, you’ll need the RepositoryUrl element in the project’s .csproj file to be set properly. Do this either by using the Project Properties screen in Visual Studio, or directly add it in the .csproj file.


Create a GitHub PAT for managing GitHub Packages

In GitHub, click on your profile icon on the top right corner and click Settings in the drop down menu. Then go to Developer Settings and then Personal access tokens. Click on the Generate new token button and select the following scopes.


Click Generate token at the bottom of the page and note down the Access Token generated for you.

Create an Azure Key Valut to hold the PAT

On the Azure Portal, create a new Key Vault and add the Access Token as a secret with the name GitHubPackagesPAT.

Create a Build Pipeline in Azure DevOps

Login to your Azure DevOps Organization and create a new Pipeline. Select the Classic Editor to build your pipeline using the wizard UI.

Select to GiHub as the source repository type. You would need to create a new Service Connection at this point, if you had not already setup a GitHub connection before. You can do this using OAuth or by setting up a new GitHub PAT granting the following permissions.

  • ​​repo
  • admin:repo_hook
  • user

Technically, you can set up one PAT with these permissions as well as the ones from the previous one. However, since you’ll be using these two tokens in different ways, I’d recommend setting up two separate tokens.

Use the ASP.NET Core template.

Pull existing NuGet Packags from GitHub at Build-time

Next, you need the build pipeline to be able to pull in NuGet packages that may already be in GitHub Packages. You can do this by creating a NuGet.config file that holds the GitHub PAT we created earlier. However, as we wouldn’t want to check this file back in to source control, we’d generate this file at build-time by pulling in the PAT from Azure KeyVault.

Click on the + button to add a task to the pipeline. From the available list of tasks, select Bash Script and move to the top of the pipeline. In the Task Configuration, select Inline and enter the following script to the Script box:

echo ‘ ‘ > NuGet.config


Be sure to replace your_github_org with the name of your GitHub Organization.

When this script runs at build-time, Azure DevOps will replace $(GitHubPackagesPAT) with a value we’ll expose through Azure KeyVault. You will see how this is done later on.

Next, click on the Restore task in the pipeline (which should be the 2nd task), and select Feeds from my NuGet.config option under Feeds to use. In Path to NuGet.config just type in NuGet.config as the above script will create the file at the root.

Push the built NuGet package to GitHub Packages

Remove the last two tasks (Publish and Publish Artifact) tasks from the pipeline. Then add a NuGet task at the end. Configure the task as below, setting the Command to push. Be sure to change Path to NuGet package(s) to publish to,


Select the External NuGet server (including other accounts/collections) under Target feed location. Then create a new service connection for the NuGet server.


Note that your Feed URL will take the form of<em>your_github_org</em>/index.json.

The username will also be your_github_org.

The pipeline tasks are now setup. Hit Save (rather than Save & Queue) to save up to now.

Setup Pipeline Variables

Under Pipeline on the left navigation pane, click on Library. Click + Variable group button.

Give the Variable group a name and turn on the option to Link secrets from Azure key vault as variables.

Switch to the Variables tab and click on Variable Groups. Now click the Link variable group button. Pick your Azure Subscription and Authorize it. Then pick the key vault and authorize it.

Now, click + Add button under Variables and pick GitHubPackagesPAT from the popup window. Click Save.


Now go back to your pipeline and switch to the Variables tab. Then click on Variable groups and then Link variable group button. From the Link variable group flyout, select the variable group you created earlier and click Link.


You have just setup the mapping for the $(GitHubPackagesPAT) variable you used in the Bash script.

Queue the Pipeline

Can go ahead and do a bit more configuration on Triggers and Options tab in the pipeline. However, as far as the core build pipeline is concerned, you are ready to execute. You can go ahead and queue it now.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.