Irbisa · Cheatsheet

Packages & Dependencies

Version constraints, pubspec.lock, version solving, overrides, publishing, melos, upgrades

Middle Developer · 19 questions

  1. 01

    What is the difference between a Dart package, a Flutter package and a Flutter plugin?

    A Dart package is any folder with a pubspec.yaml; a Flutter package is one that depends on the Flutter SDK; a plugin is a Flutter package that also carries platform code (Kotlin, Java, Swift, Objective-C, C/C++) that the app links in at build time.

    # A plugin's pubspec.yaml: the `plugin:` block is what makes it onename: battery_levelenvironment:  sdk: ^3.9.0  flutter: '>=3.35.0'…
  2. 02

    What is the difference between dependencies, dev_dependencies and dependency_overrides in pubspec.yaml?

    dependencies are what your code needs to run and are inherited by anyone who depends on you; dev_dependencies are tools for working on the package (tests, codegen, lints) and are never inherited; dependency_overrides force a version on the whole graph, and only in the root package.

    dependencies:  dio: ^5.9.0  json_annotation: ^4.9.0     # lib/ imports the annotations dev_dependencies:  build_runner: ^2.5.0        # runs on your machine and in CI only…
  3. 03

    Should you commit pubspec.lock, and does the answer differ for an app and for a published package?

    An app always commits pubspec.lock.

  4. 04

    What is the difference between pub get, pub upgrade and pub upgrade --major-versions?

    pub get reuses the versions in pubspec.lock and solves only what is new; pub upgrade re-solves for the newest versions your constraints allow; --major-versions also rewrites the constraints in pubspec.yaml to cross a major version.

    $ flutter pub outdated# Package         Current  Upgradable  Resolvable  Latest# dio             5.7.0    5.9.0       5.9.0       5.9.0# acme_analytics  1.9.4    1.9.6       2.3.0       2.3.0 $ flutter pub get                 # dio stays on 5.7.0: the lock wins…
  5. 05

    Which versions can pub pick for each constraint below, and why does intl refuse 0.21.0 while dio moves to 5.9.0?

    dependencies:  dio: ^5.7.0  intl: ^0.20.2  uuid: 4.5.1  web_socket_channel: '>=3.0.0 <3.0.3'  crypto: any

    A caret allows everything up to the next breaking version, and below 1.0.0 the minor number counts as breaking: ^5.7.0 is >=5.7.0 <6.0.0, but ^0.20.2 is only >=0.20.2 <0.21.0.

  6. 06

    What are the trade-offs of hosted, path and git dependencies, and when is pointing at a GitHub branch acceptable?

    A hosted dependency is a version range the solver can negotiate; path and git are one fixed version, and a package using either cannot go to pub.dev.

    dependencies:  dio: ^5.9.0                       # hosted on pub.dev   acme_domain:    path: ../packages/acme_domain   # inside this repo only…
  7. 07

    How do you share private packages between several of your company's apps?

    Either as git dependencies pinned to tags, which needs no infrastructure, or through a private pub repository, which keeps real version solving.

    # The shared package: can only ever be published to the private servername: acme_uiversion: 3.2.0publish_to: https://pub.acme.internal ---…
  8. 08

    flutter pub get fails with "version solving failed" and a long "Because…" chain. How do you find and fix the actual conflict?

    Read from the bottom: the last sentence names your package and the two dependencies that cannot coexist; the first Because names the shared package they disagree about.

    $ flutter pub getBecause every version of flutter_localizations from sdk depends on intl 0.20.2  and acme_analytics >=2.1.0 depends on intl ^0.21.0, flutter_localizations  from sdk is incompatible with acme_analytics >=2.1.0.So, because checkout_app depends on both flutter_localizations from sdk  and acme_analytics ^2.1.0, version solving failed.…
  9. 09

    What does dependency_overrides actually switch off, and why is it a last resort?

    It tells the solver to use your chosen version of a package everywhere in the graph and to ignore every constraint other packages put on it, so pub get turns green on a combination nobody has tested.

    dependencies:  acme_analytics: ^2.1.0      # needs intl ^0.21.0  flutter_localizations:    sdk: flutter              # pins intl exactly # wrong: pub get is green, the combination is untested…
  10. 10

    After a Flutter upgrade pub get fails with "requires SDK version >=2.7.0 <3.0.0" on a package you don't own. What happened, and what are your options?

    That package's own environment: sdk: range excludes your Dart version, so pub drops every version of it from the solve.

  11. 11

    Your package is at 1.2.0 and the next release makes the three changes below. Is that a patch, a minor or a major?

    // acme_toast 1.2.0, publishedclass Toast {  Toast({required this.message, this.seconds = 3});  final String message;  final int seconds;} enum ToastStyle { info, error } // Next release:// 1. Toast's constructor gains `required this.icon`.// 2. ToastStyle gains a third value, `warning`.// 3. A new top-level function `showToast(Toast toast)` is added.

    A major, 2.0.0: changes 1 and 2 can each stop a consumer's code from compiling, which is what breaking means.

  12. 12

    How do you structure, version and publish a package to pub.dev, and what can you never undo?

    Put the public API in lib/ and the implementation in lib/src/, add README.md, CHANGELOG.md, LICENSE and an example/, run dart pub publish --dry-run, then publish.

    acme_result/  lib/    acme_result.dart     # public API: export 'src/result.dart' show Result;    src/      result.dart        # implementation, never imported by consumers  example/…
  13. 13

    What do pub workspaces change in a monorepo, and what is Melos still needed for?

    A workspace (Dart 3.6+) makes the whole repo one resolution: one pubspec.lock, one pub get at the root, and the same version of each dependency in every package.

    # pubspec.yaml at the repo rootname: acme_workspacepublish_to: noneenvironment:  sdk: ^3.9.0workspace:…
  14. 14

    A transitive dependency you never chose ships a broken patch and your build starts failing. What do you do first?

    Check whether it can reach you at all: with pubspec.lock committed and CI on pub get --enforce-lockfile, a bad upstream release changes nothing until someone upgrades on purpose.

    # 1) What moved, and who pulls it in?git diff HEAD~1 -- pubspec.lock | grep -A3 broken_jsonflutter pub deps --style=compact | grep broken_json # 2) Back to the last good resolutiongit checkout HEAD~1 -- pubspec.lock   # or the last known-good commit…
  15. 15

    Why is one plugin such as path_provider split into several packages on pub.dev, and which of them does your app depend on?

    It is a federated plugin: the Dart API, the platform interface and each platform's implementation are separate packages, so a platform can be added or fixed without the plugin's owner.

    # bar_scanner/pubspec.yaml: the app-facing packagedependencies:  flutter: { sdk: flutter }  bar_scanner_platform_interface: ^2.0.0  bar_scanner_android: ^2.1.0        # endorsed: lands in every consumer  bar_scanner_ios: ^2.1.0…
  16. 16

    Two packages in your pub workspace (or one app) need different major versions of the same dependency. Why can't pub give each its own copy, and how do you get out?

    A Dart program holds one copy of each library, identified by its package: URI, so pub resolves exactly one version of every package for the whole app.

  17. 17

    Your team upgrades dependencies twice a year and each round costs days of firefighting. How do you make upgrades routine?

    Replace the big bang with a steady stream of small, tested bumps: a bot opens grouped PRs every week, CI proves each one, and only major upgrades get a human's full attention.

    # .github/dependabot.ymlversion: 2updates:  - package-ecosystem: pub    directory: /    schedule:…
  18. 18

    How do you move an app to a new Flutter release that contains breaking changes?

    Upgrade on a dedicated branch with the version pinned for the whole team, let dart fix --apply handle the mechanical renames, then work through the breaking-change notes, the analyzer, the tests and the native build before shipping through a beta track.

    # On a dedicated branch, with the version pinned for everyonefvm use 3.38.0               # writes .fvmrc; CI reads the same file fvm flutter pub upgrade      # plugins often need releases for the new SDKfvm flutter pub outdated…
  19. 19

    A package at the centre of your app has not shipped in two years and now blocks a Dart SDK bump: fork, vendor, or replace?

    Hide the package behind your own interface first, then pick by size: replace it if a maintained alternative exists, vendor it into packages/ if you use a small slice of pure Dart, fork it by git: at a pinned commit if you need much of it and replacing is too big.