|$ curl https://forge-ai.dev/api/markdown?path=docs/npm
$cat docs/npm-—-package-management.md
updated Recently·30 min read·published

npm — Package Management

npmToolsBeginner to Advanced
Introduction

npm (Node Package Manager) is the default package manager for Node.js and the largest software registry in the world. It manages dependencies, runs scripts, publishes packages, and enforces project conventions through a standardized manifest file.

Every Node.js project revolves around three core files: package.json (the manifest), package-lock.json (deterministic lockfile), and .npmrc (configuration). Understanding how these files work together is fundamental to modern JavaScript development.

package.json

The package.json file is the entry point of any Node project. It defines metadata, dependencies, scripts, and configuration. Every property serves a specific purpose in the dependency resolution lifecycle.

package.json
JSON
1{
2 "name": "my-app",
3 "version": "1.0.0",
4 "description": "A sample Node.js application",
5 "main": "dist/index.js",
6 "scripts": {
7 "start": "node dist/index.js",
8 "build": "tsc",
9 "test": "vitest"
10 },
11 "dependencies": {
12 "express": "^4.18.2",
13 "zod": "~3.22.0"
14 },
15 "devDependencies": {
16 "typescript": "^5.4.0",
17 "vitest": "^1.6.0"
18 },
19 "peerDependencies": {
20 "react": "^18.0.0"
21 },
22 "optionalDependencies": {
23 "@img/sharp-darwin-arm64": "^0.33.0"
24 }
25}
FieldPurposeRequired
namePackage name (npm registry key)✓ (for publishing)
versionSemVer-compliant version string✓ (for publishing)
scriptsAliases for CLI commands
dependenciesPackages required at runtime
devDependenciesPackages for development only
peerDependenciesHosted by consumer (not bundled)

best practice

Always include name and version if you plan to publish. For private apps, you can omit version or set "private": true to prevent accidental publishing.
Semantic Versioning

npm uses semantic versioning (SemVer) with the format MAJOR.MINOR.PATCH. Prefix operators in version ranges control how npm resolves updates within those ranges during install.

RangeExampleAllowed Updates
^^1.2.31.x.x (major pinned, minor & patch allowed)
~~1.2.31.2.x (minor pinned, patch allowed)
exact1.2.3Only 1.2.3 (no updates)
**Any version
>=>=1.2.0 <2.0.0Custom range
version-ranges.json
JSON
1{
2 "dependencies": {
3 "express": "^4.18.0", // 4.x.x — safe for minor/patch
4 "react": "~18.2.0", // 18.2.x — only patch updates
5 "next": "14.1.0", // exact — no auto-updates
6 "typescript": ">=5.0.0 <6.0.0" // custom range
7 }
8}

info

Use ^ for most dependencies — you get the latest compatible features without breaking changes. Use ~ when you need tighter control (e.g., framework plugins). Pin exact versions for deployment-critical packages.
npm install & npm ci

The npm install command resolves the dependency tree and installs packages into node_modules. It updates package-lock.json automatically. For deterministic installs, use npm ci which strictly follows the lockfile.

terminal
Bash
1# Local install (adds to dependencies)
2npm install express
3npm install --save-dev typescript # devDependencies
4npm install --global http-server # global install
5
6# Deterministic install (CI/CD)
7npm ci
8
9# Install with exact version
10npm install zod@3.22.4
11
12# Install from lockfile only
13npm ci --only=production
14
15# Audit after install
16npm audit
CommandLockfileUse Case
npm installUpdates itLocal development, adding deps
npm ciIgnores it (uses lockfile)CI/CD, reproducible builds

warning

Never run npm install in CI pipelines. Use npm ci instead — it is faster, fails if the lockfile is out of sync, and guarantees identical node_modules across environments.
Dependency Types

npm supports multiple dependency categories, each with a specific installation context and lifecycle. Choosing the correct category is critical for bundle size, security surface, and consumer experience.

dependencies

Runtime packages required for the application to function. Installed in both development and production. Examples: express, react, next.

devDependencies

Tools for development, testing, and building. Not installed in production when using NODE_ENV=production or --production. Examples: typescript, vitest, eslint.

peerDependencies

Packages the consumer must provide. Common in plugins and libraries that expect a specific version of a host framework. Not auto-installed — npm warns if missing.

optionalDependencies

Packages whose installation failure does not block the install. Used for platform-specific binaries. npm continues if the optional dep fails.

terminal
Bash
1# Install as dependency
2npm install express
3
4# Install as devDependency
5npm install --save-dev typescript
6
7# Install as optional dependency
8npm install --save-optional @img/sharp-darwin-arm64
9
10# Install with exact peer (for library authors)
11npm install --save-peer react@^18.0.0

best practice

Put build-time tools (typescript, eslint, prettier) in devDependencies. Only runtime imports should live in dependencies. This keeps production installs lean and reduces the attack surface.
package-lock.json

The lockfile records the exact version of every installed package, including transitive dependencies. It ensures reproducible installs across machines. Always commit it to version control.

package-lock.json
JSON
1{
2 "name": "my-app",
3 "lockfileVersion": 3,
4 "packages": {
5 "node_modules/express": {
6 "version": "4.18.2",
7 "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
8 "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1as+QEJmRg=",
9 "dependencies": {
10 "accepts": "~1.3.8",
11 "array-flatten": "1.1.1"
12 }
13 }
14 }
15}

warning

Never manually edit package-lock.json. Regenerate it by running npm install. If the lockfile is out of sync with package.json, npm ci will fail — this is a feature, not a bug.
Audit & Publish

npm includes built-in security auditing and package publishing workflows. Regular auditing helps catch vulnerable dependencies early in the development cycle.

terminal
Bash
1# Scan for vulnerabilities
2npm audit
3
4# Fix vulnerabilities automatically
5npm audit fix
6
7# Fix only patch updates (safer)
8npm audit fix --audit-level=moderate
9
10# Dry-run publish
11npm publish --dry-run
12
13# Publish to registry
14npm publish
15
16# Publish with access scope
17npm publish --access public
18
19# Update version and publish
20npm version patch && npm publish
🔥

pro tip

Run npm audit in CI and fail the build on high-severity vulnerabilities. Use npm audit --json for machine-readable output to integrate with your security dashboard.
.npmrc — Configuration

The .npmrc file configures npm behavior at the project, user, or global level. Settings cascade: project-level overrides user-level, which overrides global.

.npmrc
INI
1# Project-level .npmrc
2
3# Registry configuration
4registry=https://registry.npmjs.org/
5@mycompany:registry=https://npm.mycompany.com/
6
7# Authentication
8//npm.mycompany.com:_authToken=${NPM_TOKEN}
9
10# Install behavior
11save-exact=true
12save-prefix=""
13audit-level=high
14engine-strict=true
15
16# Package publish
17access=public
18tag=latest

info

Use engine-strict=true to enforce Node.js version requirements from package.json's engines field. This prevents installing incompatible versions that could cause runtime failures.
npm Workspaces

npm workspaces enable monorepo management by allowing multiple packages to share a single node_modules and lockfile. This reduces duplication and simplifies cross-package development.

package.json
JSON
1{
2 "name": "my-monorepo",
3 "private": true,
4 "workspaces": [
5 "packages/*",
6 "apps/*"
7 ],
8 "scripts": {
9 "build": "npm run build --workspaces",
10 "test": "npm run test --workspace=@my/app"
11 }
12}
terminal
Bash
1# Install all workspaces
2npm install
3
4# Run script across all workspaces
5npm run build --workspaces
6
7# Run script in specific workspace
8npm run test --workspace=@my/app
9
10# Add dependency to specific workspace
11npm install lodash --workspace=@my/app
12
13# List workspace tree
14npm ls --workspaces

best practice

Use workspaces when you have multiple packages that share dependencies or need to be developed together. Set "private": true on the root package.json to prevent accidental publishing of the monorepo container.
$Blueprint — Engineering Documentation·Section ID: NPM-01·Revision: 1.0