Terminology
This is an oversimplification, but a semantic version consists of 3 parts: the major version, minor version, and patch version. For example, 1.2.3 has a major version of 1, a minor version of 2, and a patch version of 3.
Example*
For the examples below, assume that the current package is app and it depends on dep1. The published versions of dep1 are:
{ "dist-tags": { "latest": "1.2.2" }, "versions": [ "1.2.2", "1.2.1", "1.0.1", "1.0.0", "0.4.1", "0.4.0", "0.2.3", "0.2.0", "0.0.3", "0.0.2", "0.0.1" ] }
Tilde (~) Dependencies
I'll start with tilde because it's the most consistent. It will give you the latest patch version without changing the major or minor version.
| SemVer Range | Your node_module Version After npm update --save |
| ~1.2.1 | 1.2.2 |
| ~1.0.1 | 1.0.1 |
| ~1.0.0 | 1.0.1 |
| ~1.0.0 | 1.0.1 |
| ~0.4.1 | 0.4.1 |
| ~0.4.0 | 0.4.1 |
| ~0.2.3 | 0.2.3 |
| ~0.2.0 | 0.2.3 |
| ~0.0.3 | 0.0.3 |
| ~0.0.2 | 0.0.3 |
| ~0.0.1 | 0.0.3 |
Caret (^) Dependencies >= v1.0.0 (a useful oversimplification)
Most think caret dependencies work like this: It will give you the latest minor version and patch version without changing the major version.
| SemVer Range | Your node_module Version After npm update --save |
| ^1.2.1 | 1.2.2 |
| ^1.0.1 | 1.2.2 |
| ^1.0.0 | 1.2.2 |
| ^1.0.0 | 1.2.2 |
But that's not the whole picture, this is only true when the major version is > 0. The next section explains how caret dependencies work regardless of the major version.
Caret (^) Dependencies
Here's a more comprehensive explanation: Imagine the major version, minor version, and patch version are elements of an array (e.g., [major, minor, patch]). The caret dependency iterates the array until it finds the first non-zero, it "freezes" that non-zero in place, then it updates the next element(s) to the latest. In other words, assuming x, y, and z represent numbers greater than 0:
^x.y.z will update y and z to the latest. ^0.y.z will update z to the latest. ^0.0.z won't update anything, because there is no element after z.
Let's see this in action:
| SemVer Range | Your node_module Version After npm update --save |
| ^1.2.1 | 1.2.2 |
| ^1.0.1 | 1.2.2 |
| ^1.0.0 | 1.2.2 |
| ^1.0.0 | 1.2.2 |
| ^0.4.1 | 0.4.1 |
| ^0.4.0 | 0.4.1 |
| ^0.2.3 | 0.2.3 |
| ^0.2.0 | 0.2.3 |
| ^0.0.3 | 0.0.3 |
| ^0.0.2 | 0.0.2 |
| ^0.0.1 | 0.0.1 |
*: This language was taken from https://docs.npmjs.com/cli/v10/commands/npm-update#example and modified.
npm config set save-prefix=''. (Stick~in the quotes if that's what you prefer.) I personally do this and shrinkwrap for things in production.npm shrinkwrapand package-lock.json vs npm-shrinkwrap.json #toSaveYouAGoogle (or two) -- fncomp mentions above and tehfoo below. Also, mneumonic:~stays about even,^goes up a little higher.