flutterdartdart-pub

How do Dart Package Versions work & how should I version my Flutter Plugins?


I am wondering how Dart package versions are resolved in my Flutter application.

Say, I have a dependency foo and declare a dependency like this:

dependencies:
  foo: ^1.2.3

How does Dart Pub know what version to resolve / what happens when a new version is available?


Furthermore, if I want to publish my Flutter plugin to pub.dev, how do I decide when to increase what part of the version?


Solution

  • Dart package versioning

    All of this goes back to Dart package versioning, i.e. there is no distinction for Flutter plugins.

    It is based on SemVer 2.0.0-rc.1 (Semantic Versioning). For Dart packages, the gist of the convention is as follows:

    <1.0.0 >=1.0.0
    0.major.minor+patch major.minor.patch

    Note that Pub also supports pre-release versions denoted by:

    <1.0.0 >=1.0.0
    0.major.0-prerelease.patch major.0.0-prerelease.patch

    Example versions might be 0.6.0-nullsafety.0 (with a patch version of 0.6.0-nullsafety.1) or 2.0.0-dev.1.

    Learn more about Dart's package versioning.

    Resolving versions

    To get a basic understanding of what problem the version resolving tries to solve, you can read through the Resolving shared dependencies section of Dart's package versioning article. The aspect of version resolving that I will look at here is the caret syntax.

    Caret ^ syntax is the standard syntax for resolving versions in Dart and closely connected to the versioning tables above. Whenever you define a dependency using foo: ^1.0.0, there is a bit of logic involved to determine which versions can be resolved from that string.

    In general, ^ matches up to major versions. This means that whenever you have a breaking change in your API, you will want to bump the major version because then dependants will not automatically be upgraded to your next package version. I will try to illustrate the matching in a table again:

    ^0.4.2+1 ^1.3.0
    >=0.4.2+1 <0.5.0 >=1.3.0 <2.0.0

    As you can see, caret syntax will match any version that is greater than or equal to the current version but smaller than the next major version.

    Note that pre-release versions are handled differently than normal (not exactly according to the SemVer spec) in Dart. You can find the source code for Pub's pub_semver tool on GitHub. It declares that pre-release versions are not matched by the caret syntax (and neither by the traditional syntax):

    ^1.0.0 matches version?
    1.4.2 yes
    1.5.0-beta yes
    2.0.0-alpha no
    2.0.0 no

    Learn more about Dart's package dependencies.

    pubspec.lock

    I quickly want to mention the role of the Pubspec lock file for dependency resolving in Dart.

    There is a straight-forward way that I think defines how package versions are fetched:

    Consequently, running pub get in your app will not unexpectedly fetch new versions. And when working with colleagues, everyone will fetch the same versions according to the pubspec.lock file when running pub get and having included the lock file in version control.

    Learn more about lockfiles in Dart.

    Best practices

    Because the Dart team recommends some best practices for versioning, I want to make sure to include them in here directly:

    Use caret syntax
    Specifying dependencies with version ranges is such as ^1.6.3 is a good practice because it allows the pub tool to select newer versions of the package when they become available. Also, it places an upper limit on the allowed version, based on an assumption that packages use semantic versions, where any version of path versioned 1.x is compatible, but where a new version 2.x would be a major upgrade that isn’t semantically compatible with 1.x versions.

    Depend on the latest stable package versions
    Use pub upgrade to update to the latest package versions that your pubspec allows. To identify dependencies in your app or package that aren’t on the latest stable versions, use pub outdated.

    Test whenever you update package dependencies
    If you run pub upgrade without updating your pubspec, the API should stay the same and your code should run as before — but test to make sure. If you modify the pubspec and update to a new major version, then you might encounter breaking changes, so you need to test even more thoroughly.