Caret vs Tilde in package.json

The package.json file is the heart of all npm packages and no matter what you might have in your project, one thing is for sure: there will always be a package.json file. Out of the many things contained within the package.json file, dependency management is what we are going to talk about today.

I think that most developers would agree that managing dependencies was never an easy task in the early days of high-level languages like JavaScript. Just ask a Java developer what life was like before Maven came along; or maybe talk to a Ruby developer about how much of an impact RubyGems has on their development. The same goes for Node.js developers. Without the dependency management of npm and package.json, life wouldn't be nearly as easy.

Carets and Tildes in Version Numbers

Within every npm-backed project, the dependencies are tracked and managed inside a package.json file via the "dependencies" JSON property. Normally these dependencies are pretty straight-forward and easy to understand. Although occasionally you may notice changes to the version numbers after using the --save option in package.json. Looking in to it further, you might see that the version numbers now have an unfamiliar character before them.

Specifically, you could end up with something like:

"dependencies": {
  "express": "^3.9.2"
}

Or another possibility is:

"dependencies": {
  "express": "~3.9.2"
}

So what is this "^" (or the "~") character actually doing up there? Don't worry, it's pretty simple, and I'll attempt to explain.

The characters that come before the version numbers are prefixes that we refer to as the caret (^) and tilde (~) signs. They are added by developers (or npm) to indicate restrictions on which software version numbers can be used as a dependency in your project. These number schemes follow a convention known as semantic versioning, or semver. The actual numbers themselves are used in the versioning system to indicate the type of changes made that led to the version number getting incremented. The numbers (3, 9, and 2) in the above example are referred to as the major, minor and patch numbers from left to right.

Before we get in to the details of what the caret and tilde actually mean, let's see a quick overview of when each of the digits in the version numbers should be incremented as changes are made to a codebase:

  1. Backward incompatible changes increment the major digit.
  2. If a new (backward compatible) change is made, then the minor digit gets incremented.
  3. Simple bug fixes (to existing functionality) increments the patch digit.

When you execute npm install in a clean project directory, the highest available software version for a dependency that is able to satisfy the version number given in package.json is installed for each dependency. So if no ^ or ~ is given, then the exact version number given is used.

However, by not specifying the precise dependency version in the package.json file and using the caret (^) or the tilde (~) signs, npm allows you to widen the accepted version range. When the --save flag is used, the default functionality is to prefix the version with the caret sign. And of course, this can be configured with the save-prefix parameter.

With respect to semantic versioning, here is a breakdown of what codebase changes the caret sign will allow:

Caret allows...

  • Backward compatible new functionalities
  • Large internal refactor
  • Bug fixes
  • Deprecation of old functionality (which is still operational)

With the caret you can get releases like 3.., where the * characters will match the highest version number available. So changes in the major digit, like 4.0.0, will not be used in this case.

Tilde allows...

  • Bug fixes

With tilde, you can get releases like 3.9.*. Only the latest bug fixes are allowed with the tilde.

So we can conclude by saying that the ~ character should be used if you want to lock in the patch number. You should use this when you are ready to accept only bug-fixes and don't want to face any possibly incompatible alterations. On the other hand, the ^ character is responsible for locking in the patch and the minor version numbers. It's to be used when you want to have backwards compatible new functionality as well as bug fixes.

Conclusion

Keep in mind that very old versions of npm do not support ^ so use it with caution. Although, any of the npm versions released in the last year or so should be fine. In most cases this shouldn't affect you.

There really isn't a "best choice" here since both have their uses in different scenarios. It all depends on your project requirements and personal preference. Just being aware of this feature in semver and npm can save you a lot of headaches, as well as some time by keeping you from having to constantly manually update your dependency versions.

Do you have a preferred choice? Have you had a bad experience with using either the caret or the tilde? Let us know in the comments!