282

Bower enables me to specify version requirements for packages using the following syntax:

"dependencies": {
  "<name>": "<version>",
},

But I have not been able to find what is the syntax to use for the <version>. I know that I can specify versions to be:

  • greater than a certain version with ">1.0.0"
  • greater than or equal to a version: ">=1.0.0"
  • or in some range: "1.0.0 - 2.0.0".

I also know that there is a common version syntax containing the tilde: "~1.0.0". But I am not sure what it means and whether it is the same as "=1.0.0".

I am also interested to know whether I am able to specify multiple non-consecutive versions, such as exactly 1.0.3 plus versions greater than 1.5.0, etc...

XML
  • 19,206
  • 9
  • 64
  • 65
Samuel Hapak
  • 6,950
  • 3
  • 35
  • 58

5 Answers5

342

In a nutshell, the syntax for Bower version numbers (and NPM's) is called SemVer, which is short for 'Semantic Versioning'. You can find documentation for the detailed syntax of SemVer as used in Bower and NPM on the API for the semver parser within Node/npm. You can learn more about the underlying spec (which does not mention ~ or other syntax details) at semver.org.

There's a super-handy visual semver calculator you can play with, making all of this much easier to grok and test.

SemVer isn't just a syntax! It has some pretty interesting things to say about the right ways to publish API's, which will help to understand what the syntax means. Crucially:

Once you identify your public API, you communicate changes to it with specific increments to your version number. Consider a version format of X.Y.Z (Major.Minor.Patch). Bug fixes not affecting the API increment the patch version, backwards compatible API additions/changes increment the minor version, and backwards incompatible API changes increment the major version.

So, your specific question about ~ relates to that Major.Minor.Patch schema. (As does the related caret operator ^.) You can use ~ to narrow the range of versions you're willing to accept to either:

  • subsequent patch-level changes to the same minor version ("bug fixes not affecting the API"), or:
  • subsequent minor-level changes to the same major version ("backwards compatible API additions/changes")

For example: to indicate you'll take any subsequent patch-level changes on the 1.2.x tree, starting with 1.2.0, but less than 1.3.0, you could use:

"angular": "~1.2"
  or:
"angular": "~1.2.0"

This also gets you the same results as using the .x syntax:

"angular": "1.2.x"

But, you can use the tilde/~ syntax to be even more specific: if you're only willing to accept patch-level changes starting with 1.2.4, but still less than 1.3.0, you'd use:

"angular": "~1.2.4"

Moving left, towards the major version, if you use...

"angular": "~1"

... it's the same as...

"angular": "1.x"
  or:
"angular": "^1.0.0"

...and matches any minor- or patch-level changes above 1.0.0, and less than 2.0:

Note that last variation above: it's called a 'caret range'. The caret looks an awful lot like a >, so you'd be excused for thinking it means "any version greater than 1.0.0". (I've certainly slipped on that.) Nope!

Caret ranges are basically used to say that you care only about the left-most significant digit - usually the major version - and that you'll permit any minor- or patch-level changes that don't affect that left-most digit. Yet, unlike a tilde range that specifies a major version, caret ranges let you specify a precise minor/patch starting point. So, while ^1.0.0 === ~1, a caret range such as ^1.2.3 lets you say you'll take any changes >=1.2.3 && <2.0.0. You couldn't do that with a tilde range.

That all seems confusing at first, when you look at it up-close. But zoom out for a sec, and think about it this way: the caret simply lets you say that you're most concerned about whatever significant digit is left-most. The tilde lets you say you're most concerned about whichever digit is right-most. The rest is detail.

It's the expressive power of the tilde and the caret that explains why people use them much more than the simpler .x syntax: they simply let you do more. That's why you'll see the tilde used often even where .x would serve. As an example, see npm itself: its own package.json file includes lots of dependencies in ~2.4.0 format, rather than the 2.4.x format it could use. By sticking to ~, the syntax is consistent all the way down a list of 70+ versioned dependencies, regardless of which beginning patch number is acceptable.

Anyway, there's still more to SemVer, but I won't try to detail it all here. Check it out on the node semver package's readme. And be sure to use the semantic versioning calculator while you're practicing and trying to get your head around how SemVer works.


RE: Non-Consecutive Version Numbers: OP's final question seems to be about specifying non-consecutive version numbers/ranges (if I have edited it fairly). Yes, you can do that, using the common double-pipe "or" operator: ||. Like so:

"angular": "1.2 <= 1.2.9 || >2.0.0"
XML
  • 19,206
  • 9
  • 64
  • 65
  • 27
    So `~` in particular means the patch (third) number may be greater than than the one specified, e.g. `~1.2.3` is equivalent to `>=1.2.3 <1.3.0`. – z0r Oct 22 '14 at 01:03
  • 1
    Can also be used for the minor (second) number, per edits inline above. – XML Jun 27 '15 at 11:32
  • interesting, that the SemVer documentation also seems to permit the x-notation (which is a whole lot more intuitive to humans). – Frank N Jan 10 '16 at 17:16
  • 2
    x-notation is intuitive to read at first, but much less flexible. For instance, `'1.1.x' === '>=1.1.0' === '~1.1.0'`. The 1.1.0 case is easy. But x-notation can't be granular, as can `'>=1.1.4'` or `'~1.1.4'`. So, then you wind up with `'1.1.x'` in one place in your dependency list, and `'~2.7.3'` in another place. That's fine, and works, but a developer then needs to parse multiple syntaxes to read a single list. And, if you're writing packages to programmatically set the version, you want a single syntax. And, most folks want to prevent breaking changes. Hence, all problems solved with `~`. – XML Jan 11 '16 at 01:35
  • 1
    `"angular": "~1.2"` will **not** match 1.3, 1.4, 1.4.9. Also `"angular": "~1"` and `"angular": "~1.0"` are **not** equivalent. Test using http://semver.npmjs.com/ – Decima Mar 21 '16 at 14:39
  • Thank you, @Decima. I'm not sure how I bungled that one, but I did. Thanks for the great calculator, too. – XML Mar 24 '16 at 12:56
  • 1
    Had to google "grok". It's not a word we use in Australia in my experience. – Clonkex Oct 02 '17 at 23:54
  • 1
    Hah. I think "grok" is less geographical than nerd-lit cultural (and possibly age-related), @Clonkex. For future readers: it's a reference to Heinlein's _Stranger in a Strange Land_... – XML Apr 26 '18 at 11:19
  • 1
    @XML Since writing that comment I have heard other Aussies use the term. I don't think I'll ever use it, though. It's too weird. – Clonkex Apr 27 '18 at 00:33
  • I noticed that when major version number is zero there is a discrepancy in that [semver calculator](https://semver.npmjs.com/). For example, `~0.2.0` yields same version set as `^0.2.0` for **lodash** where it should include versions starting with *0.3* if they exist and they exist. Whereas it fulfills this expectation with non-zero major verisons. This also happens with other packages too. Am I missing something? – sçuçu Mar 26 '19 at 11:32
  • I _think_ that this is fixed, @sçuçu?? – XML Jul 06 '21 at 16:30
  • I guess not. I am not sure. I have a bit lost the context after over two years since I have been bumped to many major versions, as well, since then. As far as ~0.2.0 should mean a different set than ^0.2.0 does it is same. Yes, that version does not markdown. – sçuçu Jul 06 '21 at 19:17
145

Based on semver, you can use

  • Hyphen Ranges X.Y.Z - A.B.C 1.2.3-2.3.4 Indicates >=1.2.3 <=2.3.4

  • X-Ranges 1.2.x 1.X 1.2.*

  • Tilde Ranges ~1.2.3 ~1.2 Indicates allowing patch-level changes or minor version changes.

  • Caret Ranges ^1.2.3 ^0.2.5 ^0.0.4

    Allows changes that do not modify the left-most non-zero digit in the [major, minor, patch] tuple

    • ^1.2.x (means >=1.2.0 <2.0.0)
    • ^0.0.x (means >=0.0.0 <0.1.0)
    • ^0.0 (means >=0.0.0 <0.1.0)
Jerome Anthony
  • 7,823
  • 2
  • 40
  • 31
  • 21
    Thank you for the no nonsense, easy to read answer. I didn't have to track back or anything, just, boom, there's the answer. Well done ;) – toddmo Aug 09 '15 at 19:34
76

Bower uses semver syntax, but here are a few quick examples:

You can install a specific version:

$ bower install jquery#1.11.1

You can use ~ to specify 'any version that starts with this':

$ bower install jquery#~1.11

You can specify multiple version requirements together:

$ bower install "jquery#<2.0 >1.10"
Wilfred Hughes
  • 29,846
  • 15
  • 139
  • 192
  • 1
    I am curious about the practical use of this. Roulette installation? – gravidThoughts Aug 17 '15 at 20:36
  • Looking at @XMLilley's answer (and semver docs) 'start's with' seems wrong, as 1.12, 1.13 would also be okay, as long, as major version doesn't go up... – Frank N Jan 10 '16 at 17:15
13

You can also use the latest keyword to install the most recent version available:

  "dependencies": {
    "fontawesome": "latest"
  }
shacker
  • 14,712
  • 8
  • 89
  • 89
  • 1
    [semver](https://github.com/npm/node-semver) doesn't mention this. Where did you establish it's valid? :) It does say "`"*" := >=0.0.0` (Any version satisfies)" which is close but a bit vague as it doesn't specifically say latest so it could be first one it finds? – GazB Mar 18 '16 at 10:11
  • To be honest, it was just trial and error - I tried it and it worked! You may be correct that it's not 100% valid, but it does work. – shacker Mar 20 '16 at 16:00
7

If there is no patch number, ~ is equivalent to appending .x to the non-tilde version. If there is a patch number, ~ allows all patch numbers >= the specified one.

~1     := 1.x
~1.2   := 1.2.x
~1.2.3 := (>=1.2.3 <1.3.0)

I don't have enough points to comment on the accepted answer, but some of the tilde information is at odds with the linked semver documentation: "angular": "~1.2" will not match 1.3, 1.4, 1.4.9. Also "angular": "~1" and "angular": "~1.0" are not equivalent. This can be verified with the npm semver calculator.

Decima
  • 116
  • 1
  • 2