After moving an app and four packages into one Dart pub workspace, `dart pub get` fails on incompatible `http` majors that built fine separately; why, and what are your options?
answer
- one resolution for all members
- one version per package name
- dev_dependencies join the resolution
- upgrade --major-versions across members
- an override, once, at the root
basics
~20 sA workspace resolves every member's dependencies and dev_dependencies together, and a resolution holds one version per package, so ^0.13.0 and ^1.2.0 no longer have a solution. Migrate the lagging member rather than overriding, or keep it outside the workspace.
solid answer
~50 sBefore the move, each package had its own `pubspec.lock`, so `storage` could stay on `http: ^0.13.0` while `field_app` used `^1.2.0`, as long as the app didn't depend on `storage`. A workspace writes one lockfile for all members' `dependencies` and `dev_dependencies`, and Dart doesn't allow two versions of one package in a resolution, so the two ranges now have to intersect. dart.dev calls that a useful feature: incompatibilities surface when they arise, not when packages are first combined. The real fix is migrating `storage` to `http` 1.x; `dart pub upgrade --major-versions` rewrites constraints in every workspace pubspec. A `dependency_overrides` entry can force one version temporarily, but a package may be overridden only once in the workspace - ideally at the root - and it hides the incompatibility. A member that must stay on the old major doesn't belong in the shared resolution.
code
yaml · 9 lines# apps/field_app/pubspec.yaml (excerpt)
resolution: workspace
dependencies:
http: ^1.2.0
# packages/storage/pubspec.yaml (excerpt)
resolution: workspace
dependencies:
http: ^0.13.0 # no overlap with ^1.2.0: the shared resolution failsgo deeper
Recall that a workspace has one lockfile, so two members cannot use different versions of the same package.
Explain why the clash was invisible before - separate lockfiles, dev_dependencies resolved only for their own package - and how the solver reports it.
Choose the fix: migrate the lagging member, use upgrade --major-versions across members, keep any override single and at the root, and remove packages that are truly independent.
Weigh what the shared resolution buys - early, repository-wide agreement on versions - against the coordination cost it imposes on teams that upgrade at different speeds.
## What changed when the packages joined Picture a monorepo with a Flutter app, `apps/field_app`, and four local packages: `core`, `api_client`, `ui_kit` and `storage`. Before it became a pub workspace, every directory had its own `pubspec.yaml` **and its own `pubspec.lock`**. Each package was resolved in isolation: - `field_app` resolved its own dependencies, plus the regular `dependencies` of the packages it imports; - `storage`, which the app did not use yet, resolved separately, with `http: ^0.13.0`; - **`dev_dependencies` of a package were never part of anyone else's resolution**, since pub includes dev dependencies only for the root package being resolved. Turning the repository into a workspace changes that. Its single `pubspec.lock` contains **the resolution of all `dependencies` and `dev_dependencies` of all workspace packages**. Every constraint in every member now has to be satisfied at once. ## Why pub cannot satisfy both A Dart resolution maps each package name to **exactly one version**; Dart doesn't allow multiple versions of the same package. `http: ^0.13.0` means at least 0.13.0 and below 0.14.0, and `http: ^1.2.0` means at least 1.2.0 and below 2.0.0. The ranges do not overlap, so the solver reports that no version of `http` satisfies both members, and `dart pub get` fails for the whole repository. dart.dev presents this as a deliberate trade: a shared resolution raises the risk of conflicts, but for packages meant to be used together that is **useful** - it forces you to fix incompatibilities when they appear, rather than when someone first wires `storage` into the app. ## The options | Option | What it does | When it fits | |---|---|---| | **Migrate the lagging member** | move `storage` to `http` 1.x and raise its constraint | the normal fix | | `dart pub upgrade --major-versions` | rewrites constraints to the latest majors, in **all** workspace pubspecs at once | many members lag behind | | `dependency_overrides` | forces one version for the whole workspace | a short, documented stopgap | | Remove the member from the workspace | it resolves on its own again | the package really is independent and must stay on the old major | ## Overrides inside a workspace Overrides behave differently from a single package: - **All** `dependency_overrides` sections in workspace packages are respected, not only the root's. - A given package may be overridden **only once** in the whole workspace; dart.dev recommends keeping overrides in the root `pubspec.yaml`. - A `pubspec_overrides.yaml` next to any workspace pubspec can also carry overrides, which is handy for local experiments that should not be committed. - An override silences the solver, not the code: if `storage` really calls 0.13-only APIs, forcing `http` 1.x turns a resolution error into a compile error. ## Finding the culprit 1. Read the solver's message: it names the package and the members whose constraints clash. 2. `dart pub deps` in a workspace lists dependencies for all packages, one workspace package at a time, which shows who pulls what. 3. `dart pub outdated` lists dependencies across the workspace and shows which ones have newer majors. 4. Check `dev_dependencies` first: they are the conflicts that never showed up before the move. ## Preventing the next clash The workspace turns version drift into an immediate error, so the habits change as well: - **Upgrade shared dependencies in one change.** `dart pub upgrade` in a workspace moves the shared resolution for every member, and `--major-versions` updates the constraints in all workspace pubspecs, so a major bump lands everywhere together. - **Review `dev_dependencies` like regular ones.** Test helpers, generators and lint packages of every member now share one resolution with the app. - **Keep committed overrides rare and at the root**, each with a comment naming the member being migrated, and delete them when the migration lands. - **Run `dart pub outdated` regularly** at the repository level, so lagging majors are found before a member's upgrade collides with them. - **Question membership.** A package that deliberately follows a different upgrade cadence, such as a tool pinned to an old dependency, is better kept outside the workspace than held in place by overrides. ## Summary - One workspace means one resolution, including every member's dev dependencies. - One version per package name, so non-overlapping constraints fail at `dart pub get`. - Fix the lagging member; use a single root override only as a stopgap; keep genuinely independent packages out.
- Why did a clash in `storage`'s dev_dependencies never show up before the workspace?pub resolves dev dependencies only for the root package being resolved. Separately, `storage`'s dev dependencies were part of `storage`'s own resolution and nobody else's. In a workspace the one lockfile covers the `dev_dependencies` of every member, so their constraints now meet the app's.
- Where should a temporary override live in a workspace, and what's the limit?All `dependency_overrides` in workspace packages are respected, but a given package can be overridden only once across the workspace, so keep it in the root `pubspec.yaml`, as dart.dev recommends. For a purely local experiment, put it in a `pubspec_overrides.yaml` so it isn't committed.
A workspace is one shared pantry for several cooks: everyone must use the same flour. A cook who insists on a different brand is caught when the pantry is stocked, not in the middle of dinner service.
saying these in an interview costs you the question
- A workspace lets each member keep its own version of a shared dependency
- Only regular dependencies join the shared resolution; dev_dependencies stay per member
- Every member may override the same package however it likes
- A dependency override fixes the incompatibility, not just the resolution error
- The conflict only appears at runtime, when both members load http