home
post
versioning in npm

Versioning in NPM

Mar 24, 2024
3 min
1 chart

Overview

NPM stands for Node Package Manager. It is the largest package registry in the world. It contains hundreds of thousands of packages uploaded to it.

NPM uses SemVer by default. It allows only SemVer syntax in the package version declaration. SemVer is very powerful and simple at the same time. NPM packages using SemVer enhanced syntax to declare package dependencies. This concept makes the dependency declaration very powerful and flexible. At the other hand it can be complex to comprehend how dependencies are resolved.

Dependency declaration

NPM package can define dependency as a strict version (1.2.3) or a range of versions (1.2.x, which is resolved to 1.2.0, 1.2.1, 1.2.3, 1.2.4). You can define a range for a newest patch versions or newest minor version, or other crazy definitions are available. Using a version range definition, you have multiple versions applicable for you your dependencies or transitive dependencies. NPM will resolve a tree of dependencies according to the version declaration in the dependencies and its dependencies. Dependencies are evolving and releasing new versions constantly. Depending on the point in time, different dependencies will be resolved. How to know what dependencies are resolved? How to lock the dependencies and have a reproducible build? package-lock.json solves this problem.

package-lock.json

package-lock.json is a file (npm reference), generated in the root of a workspace/monorepo or in the package root. It contains all information about the used dependencies used in the project. It captures the concrete versions at the time it was created. This allows to:

  • have reproducible build
  • prevent npm from resolving the tree of dependencies
  • understand/introspect what is used in the project and track the evolution of dependencies

Same dependency, different version

Different dependency branches may have different versions. For example one branch using lodash@14.16.x, other brach uses lodash@14.17.x. This means that project will contain different versions of the lodash. This gives lots of flexibility in the dependency management. Because npm solves the compatibility problems and choses the right version for you. It comes with a cost of:

  • increased bundle size
  • complexity in observing the whole picture of dependencies
  • security vulnerabilities might not be fixed withing the defined ranges.

Conflicts and overrides

Conflicts can occur for an incorrect dependency declaration. Consider the case when you need to have one library in the runtime(react or components library for example). And for some reason you will have 2 libraries in the runtime which will cause discrepancies in the JS or CSS evaluation.

Another reason already mentioned in the previous section. Security vulnerability fix. For example we have a declared version of lodash@14.17.20. lodash@14.17.21 contains critical security fix, but you have no control over transitive dependency declaration.

The melanism to solve this problem is npm "overrides".

Overrides provide a way to replace a package in your dependency tree with another version, or another package entirely. These changes can be scoped as specific or as vague as desired.

Related Posts
© 2025 buzzchart.info