Introduction

When working on a software development project, your application usually is dependent on packages that help you implement features in your application in less time. As your project grows, there is a good chance that dependencies that are tied to your application will also grow with it.

This presents a problem with the packages that are tied to your application. You can end up facing two extremes: If the specifications of the dependency packages that you use are very strict, you can end up not being able to upgrade a dependency package without upgrading the packages that rely on it. This is called “version lock”. On the other hand, if the specifications of the dependency packages that you use are very loose, you can end up being complacent by assuming compatibility with new versions beyond what would be considered acceptable. This is called “version promiscuity”. Either of these scenarios can be placed under the term “dependency hell”. Dependency hell is a barrier to advancing your project.[1]

What is Semantic Versioning? And Why is it Important?

Semantic Versioning was developed as a way to help developers in determining how to properly version their software and how to increment it. There are rules for this:

  1. There has to be a declaration of a public API either through documentation or code. It must be “clear” and “precise”.[1]

  2. Once you have completed your public API, any changes that you make to it should adhere to the following format: X.Y.Z.

  • X - Major version. Breaking changes to the API. Backwards incompatible with previous versions.
  • Y - Minor version. Backwards compatible changes to the API through either “additions” or “changes”.[1]
  • Z - Patch version. Bugs have been fixed, but have no changes overall to the API.

Semantic Versioning when Dealing with Packages using npm or yarn?

In your package.json file, the packages that you use in your project have symbols next to them. They determine whether to upgrade these packages or not and how far should an upgrade go. Here are those symbols and what they stand for:

  • ^ - Upgrade minor and patch releases of a package (e.g. 0.5.0 => 0.6.0; 0.5.0 => 0.5.1).

  • ~ - Upgrade patch releases of a package (e.g. 0.1.0 => 0.1.1).

  • = or No symbol in front of the package version - Keep this version and do not upgrade (e.g. 2.1.0 or =2.1.0).

  • <= - Upgrade a package (major, minor, and patch) to any version that is less than or equal to the version used (e.g. <=1.8.5 ).

  • >= - Upgrade a package (major, minor, and patch) to any version that is greater than or equal to the version used (e.g. >=1.5.7).

  • - - Upgrade a package (major, minor, and patch) in a range (e.g. 3.0.0-3.1.1).

  • || - Set allowed versions to upgrade a package to (e.g. 3.1.0 || >=3.2.0 <3.3.0).

  • latest - Upgrade package to the latest version available (e.g. "express": "latest").

  • x - Can be used as a substitution instead of a numerical value with major, minor or patch versions:

    • * := >=0.0.0 (Any version satisfies).
    • 1.x := >=1.0.0 <2.0.0 (Matching major version).
    • 1.2.x := >=1.2.0 <1.3.0 (Matching major and minor versions).[2]

References:

  1. Semantic Versioning.
  2. Semver Documentation.