How I Built a Small Tool to Inspect Dart Package Dependencies
If you work with Flutter for long enough, you eventually run into this kind of error:
Because device_info_plus 13.2.0 depends on win32 ^6.0.1
and file_picker >=8.3.3 <12.0.0-beta.1 depends on win32 ^5.9.0,
device_info_plus ^13.2.0 is incompatible with file_picker ^11.0.2.
At first, this looks simple: two packages depend on win32, but on different versions.
The annoying part is figuring out where that dependency comes from and what version constraint a specific package version actually declares.
So I built a small tool to make that easier.
The problem
Imagine a Flutter project with:
dependencies:
file_picker: ^11.0.2
device_info_plus: ^13.2.0
Running:
flutter pub get
fails because:
file_picker
→ win32 ^5.9.0
device_info_plus
→ win32 ^6.0.1
These constraints don't overlap.
The problem becomes more interesting when the dependency isn't direct.
You might have:
my_app
└── package_a
└── package_b
└── win32
Looking only at your pubspec.yaml doesn't tell you the whole story.
Pub already knows the answer
The Dart Pub API contains the published pubspec for every package version.
For example:
curl -s https://pub.dev/api/packages/file_picker
The response contains all published versions.
We can then select a specific version with jq:
curl -s https://pub.dev/api/packages/file_picker |
jq '.versions[] | select(.version == "11.0.2") | .pubspec.dependencies'
For file_picker 11.0.2, this gives:
{
"flutter": {
"sdk": "flutter"
},
"flutter_web_plugins": {
"sdk": "flutter"
},
"flutter_plugin_android_lifecycle": "^2.0.22",
"plugin_platform_interface": "^2.1.8",
"ffi": "^2.1.3",
"path": "^1.9.0",
"win32": "^5.9.0",
"cross_file": "^0.3.4+2",
"web": "^1.1.0",
"dbus": "^0.7.11"
}
Now the problem is immediately clear:
file_picker 11.0.2
└── win32 ^5.9.0
And:
device_info_plus 13.2.0
└── win32 ^6.0.1
Turning it into a small tool
I didn't want to type the API command manually every time.
The first version is just a small Bash script:
#!/bin/bash
read -p "Package name: " PACKAGE
read -p "Version: " VERSION
echo
echo "Dependencies for $PACKAGE $VERSION:"
echo
curl -fsSL "https://pub.dev/api/packages/$PACKAGE" |
jq --arg version "$VERSION" '
.versions[]
| select(.version == $version)
| .pubspec.dependencies
'
Now I can run:
./pub_deps.sh
and enter:
Package name: file_picker
Version: 11.0.2
The tool returns the dependencies declared by that exact package version.
A more useful version
The next step is to make the tool answer a more specific question:
Package: file_picker
Version: 11.0.2
Dependency: win32
Result:
win32 ^5.9.0
And if the package doesn't directly depend on win32:
Package: some_package
Version: 2.0.0
Dependency: win32
Result:
No direct dependency on win32.
This distinction matters because a package can depend on another package that eventually depends on win32.
Direct vs transitive dependencies
There are two different situations:
file_picker
└── win32
Here, win32 is a direct dependency of file_picker.
But you can also have:
package_a
└── package_b
└── package_c
└── win32
Here, win32 is a transitive dependency.
Dart's pub deps command is useful once the project successfully resolves:
dart pub deps --style=tree
But there is an important limitation: if pub get fails, there is no resolved dependency graph to inspect.
That's exactly the situation where querying the published package metadata becomes useful.
Why I think this is useful
Package conflicts are common in Flutter projects, especially when working with plugins that depend on platform-specific packages.
The error message from Pub is technically correct, but sometimes you want to investigate the package versions yourself:
Which version introduced this dependency?
What version constraint does this package actually declare?
Did the dependency change between two releases?
Which package is preventing me from upgrading?
Instead of opening several package pages and manually searching through their versions, a small dependency inspector can answer these questions quickly.
The next step
The Bash version is only the beginning.
A proper tool could provide something like:
Dart Dependency Inspector
Package A
file_picker 11.0.2
└── win32 ^5.9.0
Package B
device_info_plus 13.2.0
└── win32 ^6.0.1
--------------------------------
CONFLICT
Required ranges:
file_picker:
>=5.9.0 <6.0.0
device_info_plus:
>=6.0.1 <7.0.0
No compatible version exists.
It could also compare package versions and show when a dependency changed between releases.
That would turn a simple API wrapper into something more useful: a small Dart/Flutter dependency investigation tool.
Sometimes a useful developer tool starts with a frustrating pub get error.
