In this article
A committed pubspec.lock helps keep a Flutter application's Dart dependencies consistent, but it does not lock the entire native build environment. If CI and local builds disagree, compare Dart resolution, native dependencies and toolchain versions as separate layers.
Dart's source-control guidance, checked October 8, 2026, distinguishes applications from reusable packages. Apply the appropriate lockfile policy to the project you actually maintain.
Compare two identified builds#
Record the local and CI source revisions, Flutter/Dart versions, lockfile checksums, native dependency files, Java/Gradle or Xcode versions and build arguments. “Same branch” is weaker evidence than the same revision and recorded inputs.
Check whether CI runs dependency resolution or an explicit upgrade. Inspect any resulting lockfile diff. If a script upgrades before every build, a committed lockfile does not guarantee the script used its original resolution.
Preserve the failing log before cleaning. It can identify the dependency or toolchain layer that actually diverged.
Use the app-versus-package distinction#
For an application, the locked dependencies describe a particular resolved set you intend to build. A reusable package has different testing responsibilities across the version constraints it promises to consumers. Dart's private-files guide explains that distinction.
Do not impose an application policy on every library without considering its compatibility testing. Likewise, do not omit an application's lockfile merely because an older package tutorial did.
Identify what the lockfile does not cover#
Native integrations may resolve through CocoaPods, Swift Package Manager, Gradle or vendored binaries. The machine supplies compilers, SDKs and other tools. Record the applicable native lockfiles and tool versions separately.
A matching Dart lockfile alongside different Xcode versions is not a fully matching iOS environment. A plugin can also fetch or depend on native components outside the Dart resolution record.
Use a layered comparison:
Layer Local evidence CI evidence
Source revision revision
Dart SDK + lockfile SDK + lockfile
Native packages relevant resolutions relevant resolutions
Toolchain compiler/SDK versions compiler/SDK versions
Build selection flavor + flags flavor + flagsThe worksheet is an investigation aid, not a claim of bit-for-bit reproducibility.
Test clean resolution carefully#
Use an isolated checkout and the intended toolchain to perform the normal dependency resolution and build. Compare changes with the committed files. Do not erase a working developer environment merely to simulate CI.
If a dependency changes, establish why: altered constraints, a different SDK, an upgrade command or an unlocked native layer. Correct the responsible cause rather than pinning an unrelated package at random.
Make upgrades deliberate#
Keep dependency upgrades reviewable, with the changed resolution files and relevant release notes. Test the app behavior affected by the changed component and retain the previous release identity for incident comparison.
A cache may hide drift on one machine, so compare a valid cache-hit run with a clean run before declaring the problem solved. Neither success proves every supported platform was exercised.
Our AI-generated code review guide is useful when a tool changes several dependency constraints at once. Require an explanation for each update and evidence that the released application's important paths still work.