javascriptnpmrustversionsemantic-versioning

How do minor/patch upgrades in exposed dependencies affect SemVer?


The SemVer Specification details what to do when dependencies are changed without updating the public API. What exactly constitutes a change to the "public API", however, is still unclear to me.

NPM Example

Consider a library which takes a peerDependency on "foo": "^1.0.0" and exposes types from this library. If I update my library to instead take a peerDependency on "foo": "^1.0.1", is this considered a breaking change to my API? I can see the following schools of thought:

Rust Example

Consider a library which takes a dependency on foo = "1.0.0". If we increase this dependency to foo = "1.0.1", would this be a breaking change to my API? In this situation, I see the following schools of thought, taking into consideration the following quote from the docs.

Multiple versions within the same compatibility range are not allowed and will result in a resolver error if it is constrained to two different versions within a compatibility range.

This last school of thought seems to mesh best with how I read the spirit of SemVer, though I'm not sure how correctly it applies in this situation. From my perspective, the exact same subset of users will be broken by this change whether or not we expose this type in our public API, and therefore whether we consider this a breaking change or not should not be affected by this fact.


Solution

  • I only answer for Rust.

    There is no definite answer in the docs, but we can infer it based on existing docs.

    The docs say that:

    Minor: adding dependencies

    It is usually safe to add new dependencies, as long as the new dependency does not introduce new requirements that result in a breaking change. For example, adding a new dependency that requires nightly in a project that previously worked on stable is a major change.

    If we consider not building because of a precise version requirement to be a breaking change, this should also be a breaking change, since introducing a dependency may cause downstream crates that specify precise version requirement that is incompatible with our version to no longer build (for example, if we add a new dependency on foo = "1.0.1", and they have a dependency on foo = "=1.0.0"). Since this is not considered a breaking change, we can infer that we should not consider precise versions when evaluating breaking changes, and therefore, updating a dependency to a semver-compatible version is not a breaking change.

    Updating a depenency to a semver-incompatible version is a breaking change only if we expose it through our public API, as it may cause downstream crates that depend both directly and through our crate on it and expect the types to match to no longer compile.