skip to content

Lockfile & Resolution

pub get resolves constraints into pubspec.lock while pub upgrade moves to newer versions; apps commit the lockfile and packages do not. Interviewers probe version-solving failures.

part ofDartoverview, primer and where to startread it →
on this pageshow

explore

questions

5

In Dart's pub tool, what is the difference between `dart pub get` and `dart pub upgrade`, and how does each treat pubspec.lock?

level: middleimportance: must knowfreq 60%

answer

  1. get honours the lockfile
  2. upgrade ignores and rewrites it
  3. unlocked deps get latest allowed
  4. upgrade one package by name
  5. --major-versions and --tighten edit pubspec

basics

~20 s

dart pub get keeps the versions already recorded in pubspec.lock and resolves only what is new or missing; dart pub upgrade ignores the lockfile and picks the newest versions the pubspec constraints allow, then writes a new lockfile.

solid answer

~40 s

`dart pub get` resolves the pubspec but **reuses the versions locked in `pubspec.lock`** wherever it can; only unlocked packages, such as a dependency you just added, get the newest version that fits, and adding one does not move the others unless it must. `dart pub upgrade` **ignores the existing lockfile** and resolves from scratch to the latest versions your constraints allow. Both download into the system cache, write `.dart_tool/package_config.json`, and write the lockfile. Neither edits your constraints, except `dart pub upgrade --major-versions`, which raises constraints past their upper bounds, and `--tighten`, which raises lower bounds to the resolved versions. `dart pub upgrade http` upgrades just `http`, and `--unlock-transitive` lets its dependencies move too.

code

bash · 12 lines
bash
# After cloning or switching branches: reproduce the locked resolution
dart pub get

# Move everything to the newest versions the constraints allow
dart pub upgrade --dry-run
dart pub upgrade

# Upgrade one package and its transitive dependencies only
dart pub upgrade --unlock-transitive http

# Raise constraints past upper bounds (edits pubspec.yaml)
dart pub upgrade --major-versions

go deeper

for a junior

Know which command to run: get after a checkout or pubspec edit, upgrade when you deliberately want newer versions.

for a middle

Explain that get reuses the lockfile while upgrade ignores it, that both stay inside constraints, and which flags edit the pubspec.

for a senior

Upgrade deliberately: dry-run, upgrade selectively with --unlock-transitive when needed, and review the lockfile diff before merging.

for a principal

Set an upgrade cadence and ownership for dependency bumps so lockfile changes land as reviewed, testable units rather than drift.

## Two files, two jobs A Dart or Flutter package has two files describing dependencies: - **`pubspec.yaml`** holds **constraints**: the ranges of versions you accept, such as `http: ^1.2.0`. - **`pubspec.lock`** holds the **resolution**: the exact version (and, for hosted packages, a content hash) that pub chose for every package in the graph, direct and transitive. The two commands differ in how they use the second file. ## `dart pub get`: keep what is locked `dart pub get` reads the pubspec and, if a lockfile exists, **uses the locked versions if possible**. Only packages that are not locked, typically ones you just added, get the latest version satisfying all constraints. Adding a dependency does not change the versions of already-acquired ones unless that is necessary to fit the new one, and removing one never changes the others. It then: 1. downloads anything missing into the **system cache** (by default `~/.pub-cache` on macOS and Linux, or `%LOCALAPPDATA%\Pub\Cache` on Windows); 2. writes `.dart_tool/package_config.json`, which maps each package name to its location so `package:` imports resolve; 3. writes `pubspec.lock`. That makes `get` the command to run after a checkout, a branch switch or a pubspec edit: it reproduces the team's resolution instead of drifting. ## `dart pub upgrade`: resolve again `dart pub upgrade` **ignores the existing lockfile** and generates a new one from scratch, using the **latest versions of all dependencies** that the pubspec constraints allow. It never goes outside those constraints, so `http: ^1.2.0` can move to the newest 1.x but never to 2.0. | | `dart pub get` | `dart pub upgrade` | |---|---|---| | Existing lockfile | reused where possible | ignored | | Unlocked or new packages | latest allowed | latest allowed | | Already-locked packages | kept | moved to latest allowed | | Edits `pubspec.yaml` | no | only with `--major-versions` or `--tighten` | ## Upgrading selectively - `dart pub upgrade http args` upgrades only the named packages; the rest stay locked unless the new versions force them to move. Their **transitive** dependencies are not upgraded by default. - `--unlock-transitive` also unlocks the named packages' transitive closure. - `--dry-run` (`-n`) reports what would change without changing it. ## Flags that rewrite the pubspec - `--major-versions` upgrades to the versions `dart pub outdated` lists as **resolvable**, **ignoring upper bounds**, and writes the new constraints into `pubspec.yaml`. Commit first so you can undo it. - `--tighten` raises each dependency's **lower bound** to the version actually resolved, useful before publishing so constraints do not claim support for versions you never tested. ## Offline Both commands accept `--offline`, which resolves using only the system cache. The catch is that the lockfile then records whatever old versions were cached; run `dart pub upgrade` once you are online again. ## In a Flutter project The `flutter` tool wraps these commands (`flutter pub get`), and Flutter's IDE plugins run `get` automatically after a pubspec edit. The lockfile semantics are pub's and are identical.

  • With Dart's pub, you add a new package to pubspec.yaml and run `dart pub get`. Can versions of packages you already had change?
    Only if necessary. Pub keeps locked versions and resolves the new package around them; it unlocks existing packages just enough to find a solution when the new package's constraints conflict with what is locked. Otherwise the lockfile diff shows only the additions.
  • What does `dart pub upgrade --tighten` change, and why would a package author run it?
    It raises each dependency's lower bound in `pubspec.yaml` to the version actually resolved and lists the changed constraints. Authors use it so the pubspec no longer claims support for old versions the package was never tested against.

The pubspec is a shopping list that says 'any 1.x milk'; the lockfile is last week's receipt. pub get buys again from the receipt, adding only new items; pub upgrade throws the receipt away and buys the newest milk the list allows.

saying these in an interview costs you the question

  • dart pub get always fetches the newest versions available
  • dart pub upgrade can move ^1.2.0 to 2.0.0 by default
  • pub upgrade rewrites the constraints in pubspec.yaml by default
  • Upgrading one named package also upgrades its transitive dependencies
  • pub get never changes pubspec.lock once it exists
open as a page

In a Flutter app's CI, what does `dart pub get --enforce-lockfile` guarantee that plain `dart pub get` does not, and should the app commit pubspec.lock?

level: middleimportance: should knowfreq 40%

basics

~10 s

Plain pub get quietly unlocks versions when the pubspec changed, a locked version vanished or the SDK changed, and it rewrites mismatched content hashes. --enforce-lockfile fails instead. Apps commit pubspec.lock; regular packages do not.

open as a page

In Dart's `dart pub outdated` output, what do the Current, Upgradable, Resolvable and Latest columns mean, and which command closes each gap?

level: middleimportance: should knowfreq 30%

basics

~20 s

Current is the locked version, Upgradable the newest your constraints allow, Resolvable the newest that works with everything else if constraints were unbounded, and Latest the newest published. pub upgrade closes Current-to-Upgradable; a constraint edit closes Upgradable-to-Resolvable.

open as a page

In a Flutter app where `flutter_localizations` needs `intl ^0.20.3` but an older package allows only `intl ^0.19.0`, how do you diagnose and fix the version-solving failure?

level: seniorimportance: should knowfreq 40%

basics

~20 s

Pub needs one intl version for the whole graph, and ^0.20.3 and ^0.19.0 do not overlap. Read the Because chain, confirm with dart pub deps, then upgrade or replace the lagging package; a dependency override is only a temporary, tested last resort.

open as a page

Where does Dart's pub store downloaded packages, and what do `dart pub cache repair`, `gc` and `clean` each do?

level: juniorimportance: nice to knowfreq 15%

basics

~10 s

Pub downloads hosted and git packages into one system-wide cache, ~/.pub-cache by default or PUB_CACHE if set. repair reinstalls cached packages, gc removes packages no current project references, and clean empties the whole cache.

open as a page