Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
181 changes: 98 additions & 83 deletions sites/docs/src/content/packages-and-plugins/dependency-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,15 @@ description: >-
When you build a Flutter app,
you often use external packages to add functionality.
Each package can depend on other packages, creating a tree of dependencies.
Understanding how Dart and Flutter manage these dependencies helps you resolve
version conflicts and keep your app stable.
Understanding how Dart and Flutter manage these dependencies helps you
resolve version conflicts and keep your app stable.

## How dependency resolution works

Your Flutter project specifies dependencies in the `pubspec.yaml` file.
When you run `flutter pub get`,
the package manager resolves the dependencies and records the exact versions in
the `pubspec.lock` file.
the package manager resolves the dependencies and
records the exact versions in the `pubspec.lock` file.

### Direct and transitive dependencies

Expand All @@ -28,7 +28,7 @@ A dependency can be direct or transitive:

**Transitive dependencies**
: The packages that your direct dependencies depend on.
You do not list these packages in your `pubspec.yaml` file,
You don't list these packages in your `pubspec.yaml` file,
but your project requires them to compile.

### The pubspec.lock file
Expand All @@ -42,60 +42,65 @@ but not for package projects.

:::note Use version ranges, not exact versions
Since `pubspec.lock` always pins exact versions for predictable builds,
you should use ranges in your `pubspec.yaml` file (possibly using
caret syntax described below).
This allows the version solver to find compatible versions of
transitive dependencies,
you should use ranges in your `pubspec.yaml` file
(possibly using caret syntax described below).
This allows the version solver to find
compatible versions of transitive dependencies,
and enables you to safely update dependencies using `flutter pub upgrade`.
:::

## The role of the version solver

Unlike some package managers,
the Dart package manager (`pub`) allows only a single version of any package in
your app's compilation tree.
the Dart package manager (`pub`) allows only a
single version of any package in your app's compilation tree.

This constraint exists for several reasons:

1. **Type safety:** If your app uses two versions of the same package,
you can get type mismatch errors.
For example, if `v1` and `v2` of a package both define a `User` class,
the Dart compiler treats them as two distinct types.
You cannot pass a `v1.User` to a method expecting a `v2.User`.
1. **Binary size:** Including multiple versions of the same package
increases the size of your application.
1. **Global state:** Many packages use global variables or singletons.
Having multiple copies of the package can lead to inconsistent state or
bugs.

The version solver's job is to look at all version constraints for your direct
and transitive dependencies and find a single concrete version for each package
that satisfies all constraints.
1. **Type safety:**
If your app uses two versions of the same package,
you can get type mismatch errors.
For example, if `v1` and `v2` of a package both define a `User` class,
the Dart compiler treats them as two distinct types.
You can't pass a `v1.User` to a method expecting a `v2.User`.
1. **Binary size:**
Including multiple versions of the same package
increases the size of your application.
1. **Global state:**
Many packages use global variables or singletons.
Having multiple copies of the package can
lead to inconsistent state or bugs.

The version solver's job is to look at all version constraints for
your direct and transitive dependencies and find a
single concrete version for each package that satisfies all constraints.

## Understand version constraints

When you declare a dependency in `pubspec.yaml`,
you specify a version constraint.
Dart packages use [Semantic Versioning](https://semver.org) (SemVer).
Dart packages use [Semantic Versioning][] (SemVer).
A version number has three parts: `major.minor.patch` (for example, `2.1.4`).

You can define version constraints in your `pubspec.yaml` file using different
syntaxes:
You can define version constraints in your `pubspec.yaml` file
using different syntaxes:

[Semantic Versioning]: https://semver.org/spec/v2.0.0-rc.1.html

### Caret syntax

The caret syntax (`^`) is the most common way to define a version constraint.
It tells the solver to use any version that is compatible with the specified
version.
It tells the solver to use any version that is
compatible with the specified version.

* For stable versions (1.0.0 and higher),
the caret allows updates that do not change the major version:
* `^1.2.3` translates to `>=1.2.3 <2.0.0`
the caret allows updates that don't change the major version:
* `^1.2.3` is equivalent to `>=1.2.3 <2.0.0`
* For pre-release/pre-1.0.0 versions,
any change in the minor or patch version can introduce breaking changes.
Therefore, the caret constraint is more restrictive:
* `^0.8.0` translates to `>=0.8.0 <0.9.0`
* `^0.0.3` translates to `>=0.0.3 <0.0.4`
* `^0.8.0` is equivalent to `>=0.8.0 <0.9.0`
* `^0.0.3` is equivalent to `>=0.0.3 <0.0.4`

### Traditional ranges

Expand All @@ -108,7 +113,7 @@ dependencies:

### Any version

If you do not specify a version constraint or use `any`,
If you don't specify a version constraint or use `any`,
the solver can choose any version:

```yaml
Expand All @@ -117,8 +122,8 @@ dependencies:
```

:::note Avoid using `any`
We don't recommend using `any` because a future package
update might introduce breaking changes that break your build.
We don't recommend using `any` because a future package update might
introduce breaking changes that break your build.
:::

## Understand dependency conflicts
Expand All @@ -128,13 +133,13 @@ incompatible versions of the same transitive dependency.

Consider this example scenario:

1. Your app depends on two direct dependencies: `package_a` and `package_b`.
1. `package_a` depends on `foo: ^1.0.0`.
1. `package_b` depends on `foo: ^2.0.0`.
1. Your app depends on two direct dependencies: `package_a` and `package_b`.
1. `package_a` depends on `foo: ^1.0.0`.
1. `package_b` depends on `foo: ^2.0.0`.

![Version solver conflict](/assets/images/docs/development/packages-and-plugins/version-solver.png)

Because `foo` cannot be both `^1.0.0` (which is `<2.0.0`) and
Because `foo` can't be both `^1.0.0` (which is `<2.0.0`) and
`^2.0.0` (which is `>=2.0.0`), the version solver fails.

When you run `flutter pub get` or try to build the app,
Expand All @@ -148,14 +153,16 @@ So, because my_app depends on both package_a ^1.0.0
and package_b ^1.0.0, version solving failed.
```

To read this error message, trace the conflict from the bottom up
in the dependency graph:
To read this error message, trace the conflict from the
bottom up in the dependency graph:

1. Identify the conflicting package (`foo`).
1. Find which packages require conflicting versions (`package_a` requires `foo
^1.0.0` and `package_b` requires `foo ^2.0.0`).
1. Check which direct dependencies pull in those conflicting packages
(`my_app` depends on both `package_a ^1.0.0` and `package_b ^1.0.0`).
1. Identify the conflicting package (`foo`).
1. Find which packages require conflicting versions.
For example, `package_a` requires `foo: ^1.0.0` and
`package_b` requires `foo: ^2.0.0`.
1. Check which direct dependencies pull in those conflicting packages.
For example, `my_app` depends on
both `package_a: ^1.0.0` and `package_b: ^1.0.0`.

## Resolve dependency conflicts

Expand All @@ -165,15 +172,15 @@ You can use the following steps to resolve dependency conflicts.

Before making manual changes, check if newer,
compatible versions of your dependencies exist.
Run the following command to upgrade your packages to the latest versions
allowed by your `pubspec.yaml` constraints:
Run the following command to upgrade your packages to the
latest versions allowed by your `pubspec.yaml` constraints:

```bash
flutter pub upgrade
```

To see which packages have newer versions available beyond your current
constraints, run:
To see which packages have newer versions available beyond
your current constraints, run:

```bash
flutter pub outdated
Expand All @@ -185,8 +192,8 @@ run `flutter pub get`.

### Use dependency overrides

If no compatible versions exist because one of the packages has not been
updated, you can force the version solver to use a specific version.
If no compatible versions exist because one of the packages hasn't been updated,
you can force the version solver to use a specific version.
Add a `dependency_overrides` section to your `pubspec.yaml` file:

```yaml
Expand All @@ -198,43 +205,51 @@ dependency_overrides:
foo: ^2.0.0
```

This overrides all constraints for `foo` and forces the version solver to use
`^2.0.0`.
This overrides all constraints for `foo` and
forces the version solver to use `^2.0.0`.

> [!WARNING]
> Use dependency overrides only as a temporary fix.
> Bypassing the version solver can cause compilation errors or runtime crashes
(such as `NoSuchMethodError`) if the packages are not actually compatible.
> Thoroughly test your app after applying an override.
:::warning
Use dependency overrides only as a temporary fix.
If the packages aren't actually compatible,
bypassing the version solver can cause
compilation errors or runtime crashes (such as `NoSuchMethodError`).
Thoroughly test your app after applying an override.
:::

> [!NOTE]
> Dependency overrides only apply to the root package.
> If you are developing a package to publish to pub.dev,
> do not include `dependency_overrides` in your `pubspec.yaml` file because
> other projects that depend on your package will ignore them.
:::note
Dependency overrides only apply to the root package.
If you're developing a package to publish to pub.dev,
don't include `dependency_overrides` in your `pubspec.yaml` file because
other projects that depend on your package will ignore them.
:::

### Support the ecosystem

If a package is unmaintained or slow to update, you can help resolve the issue:

1. **File an issue:** Search the package's repository for existing issues or
file a new issue to notify the maintainer.
1. **Submit a pull request:** If you can fix the conflict, fork the package
repository, update the constraints, and submit a pull request.
1. **Use a git or path dependency:** While waiting for the maintainer to merge
your pull request, you can point your `pubspec.yaml` to your fork or a local
copy:
```yaml
dependencies:
package_a:
git:
url: https://github.com/your-username/package_a.git
ref: update-foo-dependency
```
If a package is unmaintained or slow to update,
you can help resolve the issue:

1. **File an issue:**
Search the package's repository for existing issues or
file a new issue to notify the maintainer.
1. **Submit a pull request:**
If you can fix the conflict, fork the package repository,
update the constraints, and submit a pull request.
1. **Use a git or path dependency:**
While waiting for the maintainer to merge your pull request,
you can point your `pubspec.yaml` to your fork or a local copy:

```yaml
dependencies:
package_a:
git:
url: https://github.com/your-username/package_a.git
ref: update-foo-dependency
```

## Learn more

For more information on how Dart manages dependencies, see the following resources:
For more information on how Dart manages dependencies,
see the following resources:

* [Package versioning][] on dart.dev
* [Pub dependencies][] on dart.dev
Expand Down
Loading