Natalie Weizenbaum and I used SemVer when we created pub, the package manager for Dart. It was a good choice, but we definitely ran into some subtle problems over the years. Briefly:
* Like Steve notes, Semver doesn't specify any syntax and semantics ranges, constraints, or other "groups of versions". Every package manager just rolls its own thing, hopefully in a mostly compatible way.
* SemVer used to specify an ordering for build versions ("1.2.3+1" versus "1.2.3+2") and then later removed that. Pub still uses the older semantics because a package manager has to do something. If the user requests "foo 1.2.3" and both "1.2.3+1" and "1.2.3+2" exist, what's the package manager supposed to do? Pick randomly? So we still technically use the older SemVer spec where this ordering is defined.
* It's hard for a package to transition into a period of experimental development. Let's say you maintain foo which has lots of users. Foo 1.2.3 is out and lots of people are using it. You want to start working on a major, breaking revision to foo. You need to do that in a way that doesn't spontaneously break existing users, but you also want to ship something so that you can get feedback from early adopters.
Right now, the way you do this is by shipping a series of pre-release versions like 2.0.0-dev.1, etc. That works, but users are often confused that a range like ">=2.0.0" does not include those dev versions, nor does "<2.0.0". It doesn't feel to me that SemVer gracefully handles the idea that previously stable packages may go through periods of instability. Pre-releases are sort of the imaginary numbers of SemVer where they don't really fit the natural linearization of version numbers.
Many projects now have "channels" of development where users can indicate whether they want to be on "stable", "dev", "bleeding edge", etc. When it comes to pre-releases and experimental versions, I think users generally want to indicate whether they want to be on the bleeding edge or not. Today, at least in pub, they have to indicate that using some carefully crafted version constraint that only includes pre-releases. It would be nice if that was a more direct way to express that.
(The fact that SemVer doesn't define ranges compounds this. I think our interpretation of ranges mostly follows npm.)
How pre-release versions are handled, or should be handled is definitely the biggest areas for improvement I've run into.
It's often unclear what one should expect tooling to do, with regard to computing/comparing ranges/versions there. Or even what one should expect such numbers to mean even as a human, with regard to changes from adjacent versions. It's not entirely clear to me even what would be the most useful understanding/requirements to have in this area, what it _should_ be. In practice, there is a lot of confusion, and inconsistency between tools.
Possibly because semver assumes just a one-dimensional list of ordered versions (reasonable, do the stupidest thing that might work and actually be implemented and adopted), but the pre-release issue really introduces a second axis. It's not clear to me what the solution is.
And, if someone from Dart wants to get involved, please open an issue on the repository. We needed to start somewhere, but also don't want to exclude other package managers, either.
One could argue that if you are about to majorly break back compat, that you should just rename your project. Even calling it `foo2` is better than pretending it's `foo 2.0`. It may slow adoption of your new work, but at least it's staying honest.
SemVer doesn’t seem to distinguish between “major” and “minor” breaking changes, instead saying all breaking changes are major version changes. So making new major versions cheap seems like a good way to document any breaking changes, even if they are “minor” breaking changes.
Natalie Weizenbaum and I used SemVer when we created pub, the package manager for Dart. It was a good choice, but we definitely ran into some subtle problems over the years. Briefly:
* Like Steve notes, Semver doesn't specify any syntax and semantics ranges, constraints, or other "groups of versions". Every package manager just rolls its own thing, hopefully in a mostly compatible way.
* SemVer used to specify an ordering for build versions ("1.2.3+1" versus "1.2.3+2") and then later removed that. Pub still uses the older semantics because a package manager has to do something. If the user requests "foo 1.2.3" and both "1.2.3+1" and "1.2.3+2" exist, what's the package manager supposed to do? Pick randomly? So we still technically use the older SemVer spec where this ordering is defined.
* It's hard for a package to transition into a period of experimental development. Let's say you maintain foo which has lots of users. Foo 1.2.3 is out and lots of people are using it. You want to start working on a major, breaking revision to foo. You need to do that in a way that doesn't spontaneously break existing users, but you also want to ship something so that you can get feedback from early adopters.
Right now, the way you do this is by shipping a series of pre-release versions like 2.0.0-dev.1, etc. That works, but users are often confused that a range like ">=2.0.0" does not include those dev versions, nor does "<2.0.0". It doesn't feel to me that SemVer gracefully handles the idea that previously stable packages may go through periods of instability. Pre-releases are sort of the imaginary numbers of SemVer where they don't really fit the natural linearization of version numbers.
Many projects now have "channels" of development where users can indicate whether they want to be on "stable", "dev", "bleeding edge", etc. When it comes to pre-releases and experimental versions, I think users generally want to indicate whether they want to be on the bleeding edge or not. Today, at least in pub, they have to indicate that using some carefully crafted version constraint that only includes pre-releases. It would be nice if that was a more direct way to express that.
(The fact that SemVer doesn't define ranges compounds this. I think our interpretation of ranges mostly follows npm.)