# 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:

```text
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:

```yaml
dependencies:
  file_picker: ^11.0.2
  device_info_plus: ^13.2.0
```

Running:

```bash
flutter pub get
```

fails because:

```text
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:

```text
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:

```bash
curl -s https://pub.dev/api/packages/file_picker
```

The response contains all published versions.

We can then select a specific version with `jq`:

```bash
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:

```json
{
  "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:

```text
file_picker 11.0.2
    └── win32 ^5.9.0
```

And:

```text
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:

```bash
#!/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:

```bash
./pub_deps.sh
```

and enter:

```text
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:

```text
Package: file_picker
Version: 11.0.2
Dependency: win32

Result:
win32 ^5.9.0
```

And if the package doesn't directly depend on `win32`:

```text
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:

```text
file_picker
└── win32
```

Here, `win32` is a direct dependency of `file_picker`.

But you can also have:

```text
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:

```bash
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:

```text
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:

```text
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.
