npm Repositories, Scoped Packages, Metadata, Tokens, Proxying, and JavaScript Supply Chains: Concepts, Architecture, and Mental Model
Model npm registry behavior through Nexus: package and scope identity, metadata documents and tarballs, dist-tags, hosted/proxy/group routing, scoped authentication, and dependency-confusion boundaries.
Learning objectives
- Explain npm package identity, scopes, versions, dist-tags, metadata documents, and tarball assets without treating them as one object.
- Map npm client requests onto Nexus hosted, proxy, and group repositories and identify which state is authoritative versus cached.
-
Explain registry and credential scoping in
.npmrc, including why authentication must be bound to a registry host/path. - Recognize dependency-confusion risk when internal namespaces can fall through to a public upstream.
- Inspect current Nexus/npm state before publishing or changing repository configuration.
Current lab baseline. Nexus Repository Community
Edition 3.95.0, Java 21 on the Nexus side, a current npm 12 client,
and loopback Nexus URL http://127.0.0.1:8081. npm group
publication through a configured writable member is a Nexus
Repository Pro feature; the mandatory Community
path publishes directly to hosted and reads through the group.
1. The practical problem: npm has more than “a package file”
Chapter 06 used Maven coordinates and repository metadata. npm has the same broad producer → repository → consumer shape, but its protocol is different. A client first asks a registry for a package metadata document. That document describes versions, distribution tags, tarball URLs, integrity values, dependencies, and other package fields. The client then fetches the selected tarball asset. If you diagnose only the tarball, you can miss a stale or misrouted metadata document; if you inspect only a package page in the UI, you can miss the registry URL or credential path the client actually used.
The operating model therefore separates package identity, registry metadata, immutable package-version tarballs, mutable dist-tags, Nexus database records, blob content, proxy cache, npm's local cache, and authentication state. These are related, but none is a synonym for “the npm package.”
2. Package identity: unscoped and scoped names
An unscoped package is identified by a name such as
left-pad. A scoped package adds a namespace prefix such
as @learner-example/ch07-demo. The scope is part of the
package name, not merely a UI folder. npm can map a scope to a
specific registry, so every request for
@learner-example/* can be forced toward an internal
Nexus endpoint while unrelated public packages use another
controlled endpoint.
| Concept | Example | Operational meaning |
|---|---|---|
| Package name | @learner-example/ch07-demo |
Logical package identity; the scope is part of the name. |
| Version | 1.0.0 |
Published version identity. npm publication rejects reusing an existing name/version combination. |
| dist-tag | latest, candidate |
Mutable label that points to a version; it is not artifact identity. |
| Metadata document | Registry JSON for the package | Lists versions, dist-tags, tarball URLs, integrity and package metadata. |
| Tarball | ch07-demo-1.0.0.tgz |
Compressed package bytes selected by metadata. |
| Integrity | typically SHA-512 SRI data | Detects byte changes against expected registry metadata; not proof of trusted provenance. |
3. npm request flow through Nexus
flowchart LR C[npm client] -->|metadata request| G[npm group] G --> H[internal npm hosted] G --> P[npm proxy] P --> U[registry.npmjs.org] H --> D[(Nexus database records)] P --> D H --> B[(blob store tarballs/metadata assets)] P --> B D --> G B --> G G -->|package metadata + tarball| C
The client uses the group as one read endpoint. The group searches its members in configured order. Internal packages should normally be found in the internal hosted member before a public proxy is allowed to satisfy the same namespace. The proxy is a managed cache of the public upstream; it is not the authoritative place to publish internal packages. The hosted repository is organization-controlled origin storage.
On current Nexus releases, npm groups can optionally route writes to a designated hosted member, but Sonatype documents that capability as Pro-only. That exception does not change the underlying ownership model: the selected hosted member stores the package.
4. Metadata, tarballs, and dist-tags are different state
Publishing
@learner-example/ch07-demo@1.0.0 creates/updates the
package metadata and stores a tarball. A later
npm dist-tag add @learner-example/ch07-demo@1.0.0 candidate
changes a pointer in package metadata; it does not rewrite the 1.0.0
tarball. If the tag moves to 1.1.0 tomorrow,
@candidate resolves differently while
@1.0.0 remains the same version identity.
This distinction is critical in CI/CD. Deployment records should
capture the immutable package version and tarball integrity/digest.
A dist-tag is useful for channels such as candidate or
latest, but it should not be the only evidence of what
was tested or released.
5. Registry selection and credential scoping
npm chooses a registry from configuration. Unscoped packages use the
default registry. A scope can have its own registry
mapping. Authentication settings such as
_authToken must be scoped to a registry host/path;
current npm documentation explicitly warns against unscoped auth
because credentials could be sent to the wrong registry.
registry=http://127.0.0.1:8081/repository/academy-ch07-group/
@learner-example:registry=http://127.0.0.1:8081/repository/academy-ch07-group/
; Authentication, when needed, must be scoped to the exact registry path.
; Do not commit a real token.
//127.0.0.1:8081/repository/academy-ch07-hosted/:_authToken=${NPM_TOKEN}
The example demonstrates structure only. In the mandatory lab, npm
writes a transient bearer credential to a private, disposable
.npmrc after interactive login. That file lives under
the lab directory rather than in the user's normal home directory,
and it is never printed into evidence.
6. Three things people call “npm tokens”
Terminology matters. npmjs.com has its own access-token models.
Nexus can use the npm Bearer Token Realm so
npm login --auth-type=legacy authenticates an existing
Nexus user and stores a registry-scoped bearer credential for the
npm client. Separately, Nexus Repository Pro has a
User Token feature that substitutes token
credentials for a Nexus user across tools. Do not conflate those
mechanisms or assume a public npm token works against Nexus.
For Community Edition training, use the npm Bearer Token Realm with a disposable local user or a carefully scoped basic-auth fallback. Pro User Tokens are optional architecture material, not a mandatory lab prerequisite.
7. Dependency confusion is a routing and namespace problem
Suppose your application depends on
@learner-example/payments and your internal group
searches a public proxy before the internal hosted repository, or
your client bypasses Nexus and sends that scope to the public
registry. An attacker-controlled public package with a colliding
name can become a candidate. A strong design combines scope
ownership, group member order, Nexus routing rules where
appropriate, and network/client policy that prevents uncontrolled
public fallback.
Important: a scope name alone is not a security boundary. It becomes meaningful only when client configuration, repository ordering, authorization, and egress policy consistently enforce where that scope may resolve from.
8. Read-only inspection before mutation
Before creating Chapter 07 repositories, record the current instance and client state. In Nexus, inspect Settings → Repository → Repositories and note existing npm hosted/proxy/group repositories, their URLs, member order, blob stores, remote URL, and online status. In npm, inspect configuration without exposing secrets.
set -eu
LAB="${TMPDIR:-/tmp}/nexus-ch07-inspect"
mkdir -p "$LAB/cache"
chmod 700 "$LAB"
export NPM_CONFIG_USERCONFIG="$LAB/npmrc"
export NPM_CONFIG_CACHE="$LAB/cache"
printf 'node: '; node --version
printf 'npm: '; npm --version
npm config get registry
npm config get @learner-example:registry || true
# Show effective keys carefully; do not capture real auth lines in shared evidence.
npm config ls --location=user | sed -E '/(_auth|_authToken|password|token)/Id'
On Windows PowerShell, use a directory under $env:TEMP,
set $env:NPM_CONFIG_USERCONFIG and
$env:NPM_CONFIG_CACHE, and remove credential-bearing
lines before sharing output. The goal is to prove which
configuration file and registry are active, not to dump secrets.
9. Why this matters in DevOps
npm is frequently used by both humans and automated builds, and package installation can execute lifecycle scripts. A production-grade repository path must therefore make identity, registry selection, authentication, public-upstream mediation, cache state, and package integrity observable. “npm install succeeded” is only a transport outcome; it is not proof that the intended namespace, version, provenance, vulnerability policy, or lifecycle-script policy was correct.
Knowledge check
What is the difference between a package version and a dist-tag?
A version is the package identity selected by semantic-version rules; a dist-tag is a mutable label that points to a version. Moving a tag does not change the versioned tarball.
Why should authentication in .npmrc be scoped to a registry URL?
So npm does not send a credential to an unrelated registry host or path. Current npm configuration rules require auth values to be registry-scoped.
Does a Nexus npm proxy own an internally published package?
No. A proxy represents cached remote content. Internal publication belongs in a hosted npm repository, even when clients read through a group.
Can a scope by itself prevent dependency confusion?
No. Scope-to-registry mapping, group order, routing/egress policy, authorization, and controlled public fallback must reinforce the namespace boundary.
Is the Nexus Pro User Token feature the same thing as the npm Bearer Token Realm?
No. The npm Bearer Token Realm supports npm client login/token behavior for Nexus users; Nexus User Tokens are a separate Pro feature used as substitute credentials across tools.
Official references and version notes
- Nexus Repository Download and current 2026 release notes — re-check the current 3.95.x self-hosted baseline before executing the lab.
- Sonatype: npm Registry — hosted, proxy, and group behavior.
- Sonatype: Configuring npm — registry configuration through Nexus.
- Sonatype: Publishing npm Packages — hosted publication and the Pro-only writable-group option.
- Sonatype: npm Security — npm Bearer Token Realm/login and basic-auth alternatives.
- Configurable Repository Fields — npm writable-group, proxy, cache, and repository options.
- npm Registry documentation and .npmrc — scope routing and registry-scoped authentication.
- npm publish and npm dist-tag — version immutability, integrity, and mutable channel labels.
Version-sensitive statements were rechecked against Sonatype and npm
primary documentation on 2026-08-26. The mandatory lab assumes Nexus
Repository Community Edition 3.95.0 and a current npm 12 client;
record npm --version and
node --version locally because npm/Node compatibility
evolves independently of Nexus. Nexus 3.87+ requires Java 21 for
supported self-hosted deployments. Re-check current release/support
pages before executing the lab.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.