Creating Your Own Private NPM Package in Azure DevOps | DevSquared

Creating Your Own Private NPM Package in Azure DevOps


A few months back, I decided to put together an internal Vue UI kit that I could reuse for some of our client projects. We learned that we almost always used the same components with the same templating style, so it made sense to create our own package to keep it easy and reusable. We ran into a few problems:

  • It was tough to find solid examples of setting up and connecting to a private NPM package (specifically for Azure DevOps).
  • There were a lot of different ways to initialize our UI kit in Vue – it was tough to find a way that was simple for our purposes.

In this post, we are going to look at setting up your first private NPM package on Azure DevOps and how to use it in your project. We are going to make a few assumptions:

  • Your NPM package is pretty simple and self-contained for the sake of simplicity.
  • You already have an Azure DevOps account setup.
  • This is not your first Vue or JS project with NPM.

Note: You can setup a private NPM and consume it other package registries, including GitHub and NPM itself. Most of these instructions will still apply.

Initializing Your Package

If you do not have NPM initialized, let’s start there with the npm init command. Be sure to follow the instructions through this process as this is what will be saved to the registry. I recommend using a low version for your first release. You should now have a package.json file that looks like the below.

  "name": "calebs-demo",
  "version": "0.1.0",
  "description": "Demo Private NPM Package",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  "author": "",
  "license": "ISC"

Let’s tweak it just a little bit by removing the scripts object, adding in an author, change the main to a new spot, and add a files array. I also like to the contributors – even if it’s only an internal package. It’s nice to recognize who has had a hand in creating something you will use everyday. Azure DevOps will also add this info and pull in the profile of users in your system, if they can be found. You should now have something like the below.

We prefer to namespace all of our internal packages using a common prefix, like “@devsquared”. This makes it easy to keep tabs of custom integrations and it keeps everything together in your package.json file.

  "name": "@devsquared/calebs-demo",
  "version": "0.1.0",
  "description": "Demo Private NPM Package",
  "main": "src/index.js",
  "author": "DevSquared",
  "files": [
  "contributors": [
      "name": "Caleb Smith"
  "license": "ISC"

The files array is a lot of folders and files that you want to include in your NPM publish. It’s common to have a bunch of documents, build files, config files, etc. in your development environment. Most of the time you do not need to share those and they just add more space to final package – keep it as lean as you can while also delivering everything that you will need for development in your other projects.

Preparing Azure DevOps

Azure DevOps refers to their NPM/Nuget registries as “artifacts” and are shared across every project – from a UI standpoint. My recommendation would be create a new project for your NPM packages, since you will want to add this to your Git repositories anyway. On the left-side nav, you will see an option for Artifacts – click on that and then “Create a New Feed” in the toolbar. Go ahead and name your feed (I.E. – ORGANIZATION NPM) and click Create.

Next, click on Connect to Feed in the toolbar, then click on NPM. You should now see a screen like below.

Connect to Feed -> NPM

I have found it easiest to handle authentication with the NPM Feed through the .npmrc file, but there are also ways to handle authentication as a Windows user and as CI build server. You can read up on more information through the official documentation:

In your NPM package folder, we will add a new file called .npmrc that will look similar to below. You can find this information by clicking on “Generate npm credentials” in the Connect to Feed modal.

; Treat this auth token like a password. Do not share it with anyone, including Microsoft support. This token expires on or before 9/22/2019.
; begin auth token
// requires email to be set but doesn't use the value
// requires email to be set but doesn't use the value
; end auth token

Publishing to Azure DevOps

We have our code ready to be pushed to the Registry! Going forward – we will make our first release, and all future updates, using the command npm publish. You will need to make sure that all publishes going forward have a different version number – NPM will throw an error in case you forget.

Using Your New NPM Package

Your NPM package is now live and privately available as long as you are authenticated. For this demo, we will continue using the same .npmrc file above in our existing project to pull in our package, but you can also continue using any authentication setup mentioned in the Microsoft Documentation.

In our existing project, we will add our .npmrc file at the root level. Next, just install your package like any other NPM package: npm install @devsquared/calebs-demo --save. If you are not authenticated, you will receive an error that the package was not found.

If we import/require the package in our existing project (IE – import from '@devsquared/calebs-demo'), it will start off by using the entry JS file, which we marked above as src/index.js. This would be the equivalent of importing the file directly (IE – import from './src/index.js'). It’s highly recommended that all of the code in your NPM package go through this single file to keep it altogether and simple to use.


You are now good to go to start using your first private NPM package! There is a lot more that you can do with packages in Azure DevOps, like delete old versions, mark packages as deprecated, or even see how often your packages are being downloaded and used across the organization.

Next, we will look at creating a Vue-specific NPM package that is ready to be consumed by any existing application.