npm
npm is a package-management tool and ecosystem around JavaScript packages. Its CLI reads a project manifest, resolves and installs dependencies, runs named scripts, and can package or publish software. The public npm registry is one destination; projects can also use configured private registries.
For day-to-day work, distinguish intent from resolution: package.json describes the project and dependency requirements; the lockfile records a resolved dependency tree. Then distinguish installation from trust: reproducibly installing a package does not prove its code is safe.
TL;DR
- Commit the project's intended manifest and applicable lockfile together.
- Use
npm cifor a locked installation when its requirements fit the workflow; investigate mismatches rather than silently rewriting them in CI. - Lifecycle scripts can execute code. Know whether the current install permits them and what an explicit script command runs.
- Workspaces organize packages inside one project; they do not automatically create runtime or security isolation.
- Inspect registry configuration and the package artifact, not only the source directory.
- Keep publishing credentials and trusted-publisher permissions separate from untrusted build execution.
Quick Example
In a new disposable directory, save this complete dependency-free package.json:
Add the complete test file example.test.mjs:
Run npm install --package-lock-only --ignore-scripts --offline to create a lockfile for this dependency-free project, then npm ci --ignore-scripts --offline and npm test. These commands are for the fresh example directory, not an existing repository. npm ci replaces that project's installation tree.
The explicit npm test runs the declared script. --ignore-scripts on an installation command does not mean a later explicit script invocation is inert. Nothing is published: the manifest deliberately marks the example private.
Core Concepts
The manifest declares the package
The package.json reference describes identity, scripts, dependency classes, file selection, and publishing-related configuration. Understand which values belong to a consumable library and which belong to an application that should remain private.
Dependency ranges describe acceptable versions; they are not a complete record of what a particular installation resolved. Review dependency and lockfile changes together so an apparently small manifest edit does not conceal a large tree change.
Locked installation is a specific workflow
The npm ci documentation explains its lockfile requirements, mismatch behavior, and replacement of an existing installation. This makes it useful for controlled automated builds, provided the lockfile and install options represent the intended project.
A lockfile is not a universal guarantee across arbitrary operating systems, runtimes, registries, and installation flags. Record the toolchain and relevant configuration. Native dependencies and optional platform-specific packages still need verification in the target environment.
Scripts are executable project behavior
npm's script guide distinguishes named and lifecycle events. An installation can invoke package code, and a named script can execute whatever command it declares with the process's available permissions.
Review code trust before exposing sensitive files or credentials to a dependency installation or build. Skipping scripts can reduce one execution path, but may also prevent required native or generated setup. Treat that choice as an explicit compatibility and trust decision rather than a complete sandbox.
Workspaces, registries, and package boundaries
The workspace guide describes managing linked local packages from a common project. Use explicit workspace commands and understand where the relevant manifest and lockfile live. A command from the repository root can have a broader scope than one package's directory suggests.
Registry configuration determines where package names resolve and where publication goes. Review scope mappings and authentication configuration before installing or publishing private packages. Avoid disclosing tokens in logs, committed configuration, or diagnostic screenshots.
Package contents form another boundary. Files present in the repository are not necessarily identical to the published tarball. Inspect the output of npm pack --dry-run and verify the applicable file inclusion rules. Note that packing-related lifecycle behavior still matters: a dry-run label is not a reason to execute an untrusted package with valuable credentials.
For a library, test the consumable artifact in a separate example consumer rather than importing directly from an unrelated source path. This catches missing files, incorrect entry points, and development-only assumptions that ordinary source tests can miss.
Separate build and publication trust
Keep untrusted contribution testing separate from package publication. A build that handles outside code should not inherit a registry credential merely because another job in the project publishes releases.
Review the current npm trusted-publishing documentation when using supported CI identity flows. Configure the exact repository, workflow, environment, and publisher relationship required by the service. Short-lived identity does not make an overbroad trust policy safe.
Before a real release, confirm package name, version, visibility, registry, artifact contents, and approval requirements. This article performs no publication and supplies no registry credentials. Its private local example is intentionally unsuitable for an accidental public release.
Best Practices
Review resolution changes
Inspect newly added packages and surprising tree changes. Reproduce installation with the intended runtime and settings. Automated audit output is useful input, not proof of absence of malicious or faulty code.
Keep scripts understandable
Use clear named commands for tests, builds, and packaging. Review inherited environment and credentials. Avoid hiding consequential publication inside a routine-looking development command.
Test the artifact boundary
Inspect and consume the packaged result in a disposable project. Confirm required files and entry points, and keep secrets and unrelated artifacts out of the package.
Common Mistakes
Regenerating the lockfile to hide CI failure
Bad: Rewrite dependency resolution during CI until installation becomes green.
Correct: Resolve the manifest/configuration mismatch in a reviewed change and commit the intended result.
Treating install as passive copying
Bad: Install arbitrary packages with production publishing credentials in the environment.
Correct: Separate trust contexts and review script execution and registry configuration before sensitive operations.
Testing only repository imports
Bad: Assume a library works for consumers because its source tests pass.
Correct: Test the package artifact from a clean consumer and verify file selection and entry points.
FAQ
Is npm only the public registry?
No. The CLI can use configured registries, including private ones. Inspect the effective configuration and scope mapping before relying on a destination.
Should I use npm ci locally?
It can be useful for reproducing a locked installation, but it replaces the project's current installation tree and requires a consistent lockfile. Use the workflow intentionally.
Does private: true secure the source code?
It helps prevent npm publication of that package. It is not repository access control, secret protection, or a substitute for inspecting build artifacts.
Do workspaces isolate packages?
They organize and link packages. Execution, dependency resolution, access permissions, and runtime isolation remain separate concerns.
Related Topics
- npm vs pnpm vs Yarn — Compare install modes, lock enforcement, workspaces, and migration evidence.
- Package Managers — Resolution and reproducibility concepts.
- Node.js — Runtime and module behavior.
- Software Supply Chain Security — Trust in dependencies and build outputs.
- CI Secrets and Workload Identity — Separate validation and publishing privileges.