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.
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.
# These shouldn't be on public npmnpm install @acme/auth-sdknpm install @acme/billing-corenpm install @acme/design-systemCI/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.
# Fragile: depends on Git access and branch existencenpm install git+ssh://git@github.com/acme/shared-utils.git#main
# Reliable: versioned package from your registrynpm install @acme/shared-utils@2.1.0Access 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) — unscoped packages are not supported - 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 pricing, typically $10,000+/year)
- npm was acquired by GitHub — 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 20+ package formats.
Pros:
- Universal format support
- Mature enterprise features
- Virtual repositories for aggregation
Cons:
- Consumption-based pricing creates unpredictable bills
- Complex setup and administration
- Expensive support contracts
Pricing reality: Artifactory’s $150/month base quickly escalates. With their consumption model (storage + transfer), moderate CI/CD usage can push costs to $600-1,200/month.
CloudRepo
Managed npm registry with transparent, predictable pricing.
Pros:
- No egress fees —
npm installnever incurs transfer charges - 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 $199/month with unmetered data transfer and unlimited users.
Quick Comparison
| Feature | Verdaccio | GitHub Packages | Artifactory | CloudRepo |
|---|---|---|---|---|
| Setup Time | Hours | Minutes | Hours | Minutes |
| Maintenance | High | None | Medium | None |
| Scoped Packages | Yes | Yes | Yes | Yes |
| Unscoped Packages | Yes | No | Yes | Yes |
| Egress Fees | N/A | Yes | $0.75-1.25/GB | None |
| SSO/SAML | DIY | GitHub only | Extra cost | Included |
| Support | Community | GitHub support | Extra cost | Included |
| Starting Price | Free + infra | Free (limited) | $150/month + usage | $199/month |
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_REPOStep 2: Authenticate with npm
# Log in to your private registrynpm login --registry=https://YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPOStep 3: Configure .npmrc
Create a .npmrc file in your project root (recommended) or configure globally:
registry=https://YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPOalways-auth=trueStep 4: Publish Your First Package
# Publish a scoped packagenpm publish --access restricted
# Publish an unscoped packagenpm publishStep 5: Install from Your Registry
# Install works exactly like public npmnpm install @acme/shared-utilsnpm install my-internal-toolWorking with Multiple Clients
CloudRepo uses the standard npm registry protocol, so all major JavaScript package managers work out of the box.
Yarn 2+ (Berry)
npmRegistryServer: "https://YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPO"npmAlwaysAuth: truenpmAuthToken: "${NPM_TOKEN}"# Install packagesyarn install
# Publishyarn npm publishpnpm
pnpm uses the standard .npmrc file:
registry=https://YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPOalways-auth=true//YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPO:_authToken=${NPM_TOKEN}# Install packagespnpm install
# Publishpnpm publishBun
[install]registry = "https://YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPO"Or use .npmrc (Bun supports it):
# Install packagesbun install
# Publish (uses npm under the hood)bunx npm publishCI/CD Integration
GitHub Actions
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
publish: image: node:20 stage: deploy script: - echo "//YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPO:_authToken=${CLOUDREPO_NPM_TOKEN}" > .npmrc - npm publish only: - tagsJenkins
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 ''' } } } }}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.
Use always-auth
Always set always-auth=true in your .npmrc. Without it, npm may attempt unauthenticated requests to your private registry and fail.
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
registry=https://YOUR_ORG.mycloudrepo.io/repositories/YOUR_REPOalways-auth=true# 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:
# Publish a stable release (automatically tagged as "latest")npm publish
# Publish a betanpm publish --tag beta
# Promote beta to latestnpm dist-tag add @acme/sdk@2.0.0-beta.5 latestTip
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?
- Start your 14-day free trial — no credit card required
- Create an npm repository — takes 30 seconds
- Run
npm login— authenticate with your registry npm publish— your first package is live
No egress fees, no per-user pricing, no consumption meters. 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.
Questions?
We're a bootstrapped, founder-led company that believes in human support. No call centers, no ticket queues - just a real conversation with someone who can help.