Search code examples
npmversioningsemantic-versioning

Does caret (^) in semver matches pre-release when pre-release version is the latest available version?


Consider having library (e. g. NPM package) with these versions:

  • 1.0.0
  • 1.0.2
  • 1.1.0-prerelease

If I specify ^1.0.0 in my dependencies, what will be version that will be installed? 1.1.0-prerelease is the latest version, but I don't think any pre-release version satisfies range where I don't specify pre-release part. I have tried using https://semver.npmjs.com, but lodash doesn't have a situation where pre-release was also latest.


Solution

  • Typically a range with a caret (^) prefix such as ^1.0.0 does not result in the prerelease version 1.1.0-prerelease being installed.

    So given the examples provided in your question the version that will typically be installed is 1.0.2.

    Note: However, that logic may not always be the case - I'll explain why shortly.


    Example of typical logic using the Semver Calculator:

    At time of writing this, a better example to illustrate the typical logic using the Semver Calculator is to test using typescript instead of lodash.

    Using the semver calculator:

    1. Pick typescript as the package
    2. Enter a range of ^4.0.0

    As you can see it selects 4.0.2 and does not select 4.2.0-dev.20201204 (which was published to the npm registry after 4.0.2). This logic is typically what will happen.

    When may the typical aforementioned logic differ:

    You'll, have noticed that in my previous explanation I say "typically" alot. I say that because npm has a dist-tag feature that allows the publisher of a package to modify the distribution tags. A short excerpt from the documentation for dist-tag reads as follows:

    By default, the latest tag is used by npm to identify the current version of a package, and npm install <pkg> (without any @<version> or @<tag> specifier) installs the latest tag. Typically, projects only use the latest tag for stable release versions, and use other tags for unstable versions such as prereleases.

    So, if we consider again the typescript example described in the previous section. If the publisher associated the latest tag in the npm registry with version 4.2.0-dev.20201204. For example if they run the following command:

    npm dist-tag add typescript@4.2.0-dev.20201204 latest
    

    then version 4.0.2 will not be installed (given a semver range of ^4.0.0), and instead version 4.2.0-dev.20201204 will be installed.

    Similarly, given the examples provided in your question, if we were to associate the latest tag with version 1.1.0-prerelease (using the npm dist-tag ... command), and given a range specified as ^1.0.0 in the dependencies section of your package.json, then version 1.1.0-prerelease will be installed and not 1.0.2.

    Note: I would consider these scenarios described in this section as quite rare, (they're certainly not typical but useful to understand), because as stated in that previous excerpt from the docs:

    Typically, projects only use the latest tag for stable release versions


    Additional info:

    Utilize the npm view command to discover information about a package(s) dist tags, particularly the latest tag. For example:

    • The following command prints all tag information for the typescript package:

      npm view typescript dist-tags
      
    • The following command prints the version associated with the latest tag for the typescript package:

      npm view typescript dist-tags.latest
      

    For further info about distribution tags refer to adding dist-tags to packages.