Npm scopes
Azure DevOps Services | Azure DevOps Server 2022 - Azure DevOps Server 2019 | TFS 2018
Npm scopes are a way of grouping related packages together. A scope allows you to create a package with the same name as other packages created by different users without conflicts. Using scopes, you can separate public and private packages by adding the scope prefix @SCOPE_NAME and configuring the .npmrc file to only use a feed for that scope. With Azure Artifacts, you can publish and download both scoped and non-scoped packages to/from feeds or public registries. Using npm scopes is also useful with self-hosted on-premise servers that do not have internet access because setting up upstream sources in that case is not possible. Using scopes:
- We don't have to worry about name collisions.
- No need to change the npm registry in order to install or publish our packages.
- Each npm organization/user has their own scope, and only the owner or the scope members can publish packages to their scope.
Project setup
Select Artifacts, and then select Connect to feed.
Select npm, and then select Other.
Add a
.npmrc
file in the same directory as your package.json, and paste the following snippet into your file.registry=https://pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/registry/ always-auth=true
Set up credentials
Copy the following snippet into your
.npmrc
file.Organization-scoped feed:
; begin auth token //pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/registry/:username=[ENTER_ANY_VALUE_BUT_NOT_AN_EMPTY_STRING] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/registry/:_password=[BASE64_ENCODED_PERSONAL_ACCESS_TOKEN] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/registry/:email=npm requires email to be set but doesn't use the value //pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/:username=[ANY_VALUE_BUT_NOT_AN_EMPTY_STRING] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/:_password=[BASE64_ENCODED_PERSONAL_ACCESS_TOKEN] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/_packaging/<FEED_NAME>/npm/:email=npm requires email to be set but doesn't use the value ; end auth token
Project-scoped feed:
; begin auth token //pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/registry/:username=[ENTER_ANY_VALUE_BUT_NOT_AN_EMPTY_STRING] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/registry/:_password=[BASE64_ENCODED_PERSONAL_ACCESS_TOKEN] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/registry/:email=npm requires email to be set but doesn't use the value //pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/:username=[ENTER_ANY_VALUE_BUT_NOT_AN_EMPTY_STRING] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/:_password=[BASE64_ENCODED_PERSONAL_ACCESS_TOKEN] //pkgs.dev.azure.com/<ORGANIZATION_NAME>/<PROJECT_NAME>/_packaging/<FEED_NAME>/npm/:email=npm requires email to be set but doesn't use the value ; end auth token
Generate a personal access token with Packaging > Read & write scopes.
Run the following command to encode your newly generated personal access token. Paste your personal access token when prompted.
node -e "require('readline') .createInterface({input:process.stdin,output:process.stdout,historySize:0}) .question('PAT> ',p => { b64=Buffer.from(p.trim()).toString('base64');console.log(b64);process.exit(); })"
Open your
.npmrc
file and replace the placeholder[BASE64_ENCODED_PERSONAL_ACCESS_TOKEN]
with your encoded personal access token you just created.
Select Packages, and then select Connect to feed.
Select npm.
Select Generate npm credentials, and then copy the credentials and add them to your .npmrc file.
In your .npmrc file, replace registry=<YOUR_SOURCE_URL>
with @SCOPE_NAME:registry=<YOUR_SOURCE_URL>
. Make sure you add the scope and package names to your package.json file: { "name": "@SCOPE_NAME/PACKAGE_NAME" }
.
@[SCOPE_NAME]:registry=https://pkgs.dev.azure.com/[ORGANIZATION_NAME]/_packaging/[FEED_NAME]/npm/registry/
always-auth=true
{
"name": "[@SCOPE_NAME]/[PACKAGE_NAME]"
}
Upstream sources vs scopes
Upstream sources give you the most flexibility to use a combination of scoped and non-scoped packages in your feed, as well as scoped and non-scoped packages from public registries such as npmjs.com.
Scopes add another restriction when naming your packages: each package name must start with @<scope>
. If you want to publish your private packages to public registries, you must do so with the scopes intact. If you remove package scopes when deploying your packages, you'll need to update all the references in your package.json. With that in mind, scopes can be a viable alternative to upstream sources.
Related articles
Feedback
Submit and view feedback for