npm

Private npm Registry Guide: Setup, Comparison & Best Practices

Every feature on every plan, with unlimited users

See how teams move to CloudRepo

Complete guide to hosting private npm packages. Compare Verdaccio, GitHub Packages, npm Enterprise, and CloudRepo. Step-by-step setup for npm, Yarn, pnpm, and Bun.

CloudRepo Team
8 min read

Every JavaScript team eventually needs to share internal packages without publishing them to the public npm registry. Whether it’s proprietary business logic, shared UI components, or internal tooling, a private npm registry is the answer.

This guide covers why you need one, how the options compare, and step-by-step setup for npm, Yarn, pnpm, and Bun with CloudRepo. To skip to the product, see CloudRepo’s private npm registry.

Why Use a Private npm Registry?

Before evaluating solutions, let’s understand the problems a private registry solves.

Security and IP Protection

Your internal libraries contain proprietary code. Publishing them to the public npm registry exposes your intellectual property. A private registry keeps your packages secure behind authentication.

Terminal window
# These shouldn't be on public npm
npm install @acme/auth-sdk
npm install @acme/billing-core
npm install @acme/design-system

CI/CD Reliability

Depending on Git URLs or local tarballs creates fragile pipelines. A private registry provides stable, versioned packages that survive branch deletions, repository renames, and network hiccups.

Terminal window
# Fragile: depends on Git access and branch existence
npm install git+ssh://git@github.com/acme/shared-utils.git#main
# Reliable: versioned package from your registry
npm install @acme/shared-utils@2.1.0

Access Control

Control who can publish packages and who can install them. Per-user permissions and organization-level isolation keep your packages safe.

Reproducible Builds

Lock files reference registry URLs, not Git commits. A private registry ensures every npm install pulls the exact same artifacts, every time.

Comparing Private npm Registry Options

Verdaccio (Self-Hosted)

Verdaccio is the most popular open-source npm registry.

Pros:

  • Free and open source
  • Full npm compatibility
  • Proxy to public npm included
  • Active community

Cons:

  • You manage the infrastructure (servers, storage, backups, SSL)
  • No built-in high availability
  • Limited enterprise features (RBAC, audit logs)
  • Security patching is your responsibility

Best for: Small teams with DevOps capacity who want full control or need air-gapped environments.

GitHub Packages

GitHub’s built-in package registry supports npm alongside other formats.

Pros:

  • Integrated with GitHub repositories and Actions
  • Free for public packages
  • No additional accounts to manage

Cons:

  • Only supports scoped packages (@scope/package), not unscoped ones
  • Tied to GitHub ecosystem (vendor lock-in)
  • Storage and transfer limits on free tier
  • Data transfer fees on paid plans

Best for: Teams already on GitHub who only need scoped packages and want minimal configuration.

Important

GitHub Packages limitation: If you need to publish unscoped packages like my-utils (without an @scope/ prefix), GitHub Packages won’t work. CloudRepo supports both scoped and unscoped packages.

npm Enterprise (npmE)

npm’s own enterprise offering for private registries.

Pros:

  • From the npm team: maximum compatibility
  • SSO integration
  • Access management

Cons:

  • Expensive (custom, enterprise-tier pricing; npm doesn’t publish rates)
  • npm was acquired by GitHub, so the standalone enterprise product’s future is unclear
  • Overlap with GitHub Packages creates confusion

Best for: Large enterprises already invested in the npm ecosystem with budget for premium pricing.

JFrog Artifactory

The enterprise incumbent supporting 60+ package formats.

Pros:

  • Universal format support
  • Mature enterprise features
  • Virtual repositories for aggregation

Cons:

  • Consumption-based pricing creates unpredictable bills
  • Complex setup and administration
  • Community support on the Pro plan; 24/7 SLA support starts at Enterprise X

Pricing reality: Artifactory’s Pro base is $150/month at list. With their consumption model (storage + transfer), each GB above the included 25 GB adds $1.25 at the first tier, so 500 GB of monthly consumption costs $743.75 at list.

CloudRepo

A managed private npm registry with transparent, predictable pricing.

Pros:

  • Scoped AND unscoped packages (unlike GitHub Packages)
  • Works with npm, Yarn, pnpm, and Bun
  • Predictable flat-rate pricing
  • Support included from real engineers

Cons:

  • Fewer advanced features than Artifactory
  • No self-hosted option

Pricing: CloudRepo starts at $99/month billed annually, with a generous transfer allowance and unlimited users.

Quick Comparison

Feature Verdaccio GitHub Packages Artifactory CloudRepo
Maintenance High None Medium None
Scoped Packages Yes Yes Yes Yes
Unscoped Packages Yes No Yes Yes
SSO/SAML DIY GitHub only Enterprise X Included
Support Community GitHub support Community on Pro; 24/7 SLA on Enterprise X Included
Starting price Free + infra Free (limited) $150/month list + usage $99/month billed annually

Pricing your whole team for a year? Open the ROI calculator

CloudRepo includes single sign-on and human support from the people who build CloudRepo on every plan.

Features of JFrog Pro and of every CloudRepo plan
Feature JFrog Pro CloudRepo, every plan
Single sign-on (SSO) Not in Pro: JFrog lists SAML and OAuth sign-on for Enterprise X Enterprise X is for organizations who need multi-site capabilities, uptime and support guarantees, and enterprise access controls (ie. OAuth, SAML, CName). JFrog’s pricing page, archived Included
Support Community support: public documentation, a knowledge base and Stack Overflow Community Support - Available for Free solutions and Pro subscriptions - JFrog maintains public documentation, knowledge base, and engages in conversations on Stack Overflow. JFrog’s pricing page, archived Human support from the people who build CloudRepo

Setting Up CloudRepo as Your Private npm Registry

Step 1: Create Your Repository

Sign up at cloudrepo.io/signup (14-day free trial, no credit card required) and create an npm repository through the web UI.

Your registry URL will be:

https://your-org.mycloudrepo.io/repositories/your-repo

Step 2: Authenticate with npm

Terminal window
# Configure your registry, then run npm login
npm config set registry=https://your-org.mycloudrepo.io/repositories/your-repo/
npm login

npm login opens your browser, walks you through CloudRepo sign-in, and writes a repo-scoped token to ~/.npmrc automatically. For CI/CD scripts, mint an API token in the admin portal and reference it as _authToken in .npmrc instead. No browser required.

Step 3: Configure .npmrc

After npm login, your ~/.npmrc is configured automatically. For project-local config (e.g., to share with your team):

.npmrc
registry=https://your-org.mycloudrepo.io/repositories/your-repo/
//your-org.mycloudrepo.io/repositories/your-repo/:_authToken=${NPM_TOKEN}

Step 4: Publish Your First Package

Terminal window
# Publish a scoped package
npm publish --access restricted
# Publish an unscoped package
npm publish

Step 5: Install from Your Registry

Terminal window
# Install works exactly like public npm
npm install @acme/shared-utils
npm install my-internal-tool

Working with Multiple Clients

CloudRepo uses the standard npm registry protocol, so all major JavaScript package managers work out of the box.

Yarn 2+ (Berry)

.yarnrc.yml
npmRegistryServer: 'https://your-org.mycloudrepo.io/repositories/your-repo'
npmAlwaysAuth: true
npmAuthToken: '${NPM_TOKEN}'

Yarn 4.15 and later wait a day before installing a newly published version. On Yarn 4.17 and later, add this to your scope’s block to install your own packages the day you publish them. On 4.15 or 4.16, update Yarn or install the next day.

.yarnrc.yml (scoped, same-day installs)
npmScopes:
yourscope:
npmRegistryServer: 'https://your-org.mycloudrepo.io/repositories/your-repo'
npmAuthToken: '${NPM_TOKEN}'
npmMinimalAgeGate: 0

This lets Yarn install versions you published today from your own repository. Delete that line to keep Yarn’s one-day delay.

Terminal window
# Install packages
yarn install
# Publish
yarn npm publish

pnpm

pnpm uses the standard .npmrc file:

.npmrc
registry=https://your-org.mycloudrepo.io/repositories/your-repo
//your-org.mycloudrepo.io/repositories/your-repo:_authToken=${NPM_TOKEN}
Terminal window
# Install packages
pnpm install
# Publish
pnpm publish

Bun

bunfig.toml
[install.scopes]
"@yourscope" = { token = "$NPM_TOKEN", url = "https://your-org.mycloudrepo.io/repositories/your-repo/" }

Or use .npmrc (Bun supports it):

Terminal window
# Install packages
bun install
# Publish (uses npm under the hood)
bunx npm publish

CI/CD Integration

GitHub Actions

.github/workflows/publish.yml
name: Publish Package
on:
release:
types: [published]
jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://your-org.mycloudrepo.io/repositories/your-repo'
- run: npm ci
- run: npm publish
env:
NODE_AUTH_TOKEN: ${{ secrets.CLOUDREPO_NPM_TOKEN }}

GitLab CI

.gitlab-ci.yml
publish:
image: node:20
stage: deploy
script:
- echo '//your-org.mycloudrepo.io/repositories/your-repo/:_authToken=${CLOUDREPO_NPM_TOKEN}' > .npmrc
- npm publish
only:
- tags

Jenkins

Jenkinsfile
pipeline {
agent { docker { image 'node:20' } }
stages {
stage('Publish') {
steps {
withCredentials([string(credentialsId: 'cloudrepo-npm-token', variable: 'NPM_TOKEN')]) {
sh '''
echo '//your-org.mycloudrepo.io/repositories/your-repo/:_authToken=${NPM_TOKEN}' > .npmrc
npm publish
'''
}
}
}
}
}

In both, the single quotes write ${...} into .npmrc as text, and npm replaces it with the variable’s value when it runs, so the file never holds the token.

Best Practices

Scoped vs Unscoped Packages

Use scoped packages for organization-internal code and unscoped for shared libraries:

{
"name": "@acme/auth-sdk",
"version": "2.1.0"
}

Scoped packages make ownership clear and prevent naming collisions with public npm packages.

Give Each Registry a Token Line

npm sends the token on every request to the registry whose //host/path/:_authToken line matches your registry= URL, installs included, so no always-auth setting is needed (npm 11 warns that always-auth is an unknown option).

Per-Project .npmrc Over Global

Commit a .npmrc to each project rather than relying on global configuration. This ensures:

  • New developers can set up immediately
  • CI/CD environments work without extra configuration
  • Different projects can use different registries
.npmrc
registry=https://your-org.mycloudrepo.io/repositories/your-repo
# Auth token comes from environment variable — never commit tokens
//your-org.mycloudrepo.io/repositories/your-repo:_authToken=${NPM_TOKEN}

Token Management

  • Generate read-only tokens for CI/CD install steps
  • Generate publish tokens only for release pipelines
  • Rotate tokens on a regular schedule
  • Never commit tokens to source control. Use environment variables.

Version Management with Dist-Tags

Use dist-tags to manage release channels:

Terminal window
# Publish a stable release (automatically tagged as "latest")
npm publish
# Publish a beta
npm publish --tag beta
# Promote beta to latest
npm dist-tag add @acme/sdk@2.0.0-beta.5 latest

Tip

CloudRepo supports the full npm dist-tag protocol. Use tags like beta, canary, and next to manage release channels without affecting production installs.

Getting Started

Ready to simplify your JavaScript package management?

  1. Start your 14-day free trial: no credit card required
  2. Create an npm repository: takes 30 seconds
  3. Run npm login: your browser opens, you authorize once, and your repo-scoped token lands in ~/.npmrc
  4. npm publish: your first package is live

No per-user pricing. Just simple, reliable npm package hosting.


Questions about setting up your private npm registry? Our engineering team provides hands-on support for every customer. Contact us for a personalized walkthrough.

Competitor figures in this guide were read on 2026-10-06 from JFrog’s pricing (archived), JFrog’s Pro checkout (archived), JFrog’s support page (archived) and JFrog’s SAML documentation (archived). Vendors change prices and plans, so check each page before you decide.