- Dependency sources
- Version constraints
- Dev dependencies
- Dependency overrides
- Best practices
Dependencies are one of the core concepts of the pub package manager. A dependency is another package that your package needs in order to work. Dependencies are specified in your pubspec. You list only immediate dependencies—the software that your package uses directly. Pub handles transitive dependencies for you.
This page has detailed information on how to specify dependencies. At the end is a list of best practices for package dependencies.
For each dependency, you specify the name of the package you depend on and the range of versions of that package that you allow. You can also specify the source, which tells pub how to locate the package.
Here’s an example of specifying a dependency:
dependencies: transmogrify: ^1.0.0
This YAML code creates a dependency on the
using the default package repository (pub.dev) and
allowing any version from
2.0.0 (but not including
See the version constraints
section of this page for syntax details.
To specify a source that isn’t pub.dev,
For example, the following YAML code uses
to tell pub to get
transmogrify from a local directory:
dependencies: transmogrify: path: /Users/me/transmogrify
The next section describes the format for each dependency source.
Pub can use the following sources to locate packages:
A hosted package is one that can be downloaded from the pub.dev site (or another HTTP server that speaks the same API). Here’s an example of declaring a dependency on a hosted package:
dependencies: transmogrify: ^1.4.0
This example specifies that your package depends on a hosted package named
transmogrify and works with any version from 1.4.0 to 2.0.0
(but not 2.0.0 itself).
If you want to use your own package repository,
you can use
hosted to specify its URL.
The following YAML code creates a dependency on the
environment: sdk: >=2.15.0 < 3.0.0 dependencies: transmogrify: hosted: https://some-package-server.com version: ^1.4.0
The version constraint is optional but recommended. If no version constraint is
any is assumed.
Sometimes you live on the bleeding edge and need to use packages that haven’t been formally released yet. Maybe your package itself is still in development and is using other packages that are being developed at the same time. To make that easier, you can depend directly on a package stored in a Git repository.
dependencies: kittens: git: https://github.com/munificent/kittens.git
git here says this package is found using Git, and the URL after that is
the Git URL that can be used to clone the package.
Even if the package repo is private, if you can connect to the repo using SSH, then you can depend on the package by using the repo’s SSH URL:
dependencies: kittens: git: email@example.com:munificent/kittens.git
If you want to depend on a specific commit, branch, or tag,
ref key to the description:
dependencies: kittens: git: url: firstname.lastname@example.org:munificent/kittens.git ref: some-branch
The ref can be anything that Git allows to identify a commit.
Pub assumes that the package is in the root of the Git repository. To specify a
different location in the repo, specify a
path relative to the repository
dependencies: kittens: git: url: email@example.com:munificent/cats.git path: path/to/kittens
The path is relative to the Git repo’s root.
Git dependencies are not allowed as dependencies for packages uploaded to pub.dev.
Sometimes you find yourself working on multiple related packages at the same time. Maybe you are creating a framework while building an app that uses it. In those cases, during development you really want to depend on the live version of that package on your local file system. That way changes in one package are instantly picked up by the one that depends on it.
To handle that, pub supports path dependencies.
dependencies: transmogrify: path: /Users/me/transmogrify
This says the root directory for
For this dependency, pub generates a symlink directly to the
of the referenced package directory. Any changes you make to the dependent
package are seen immediately. You don’t need to run pub every time you
change the dependent package.
Relative paths are allowed and are considered relative to the directory containing your pubspec.
Path dependencies are useful for local development, but do not work when sharing code with the outside world—not everyone can get to your file system. Because of this, you cannot upload a package to the pub.dev site if it has any path dependencies in its pubspec.
Instead, the typical workflow is:
- Edit your pubspec locally to use a path dependency.
- Work on the main package and the package it depends on.
- Once they’re both working, publish the dependent package.
- Change your pubspec to point to the now hosted version of its dependent.
- Publish your main package too, if you want.
The SDK source is used for any SDKs that are shipped along with packages, which may themselves be dependencies. Currently, Flutter is the only SDK that is supported.
The syntax looks like this:
dependencies: flutter_driver: sdk: flutter
The identifier after
sdk: indicates which SDK the package comes from.
flutter, the dependency is satisfiable as long as:
- Pub is running in the context of the
- The Flutter SDK contains a package with the given name
If it’s an unknown identifier, the dependency is always considered unsatisfied.
Specifying version constraints lets people using your package know which versions of its dependencies they can rely on to be compatible with your library. Your goal is to allow a range of versions as wide as possible to give your users flexibility. But it should be narrow enough to exclude versions that you know don’t work or haven’t been tested.
The Dart community uses semantic versioning1, which helps you know which versions should work.
If you know that your package works fine with
1.2.3 of some dependency, then
semantic versioning tells you that it should work with any subsequent
stable release before
For details on pub’s version system,
see the package versioning page.
You can express version constraints using either
caret syntax (
traditional syntax (
Caret syntax is a compact way of expressing the most common
sort of version constraint.
^version means the range of all versions guaranteed to be backwards
compatible with the specified version.
^1.2.3 is equivalent to
'>=1.2.3 <2.0.0', and
^0.1.2 is equivalent to
The following is an example of caret syntax:
dependencies: path: ^1.3.0 collection: ^1.1.0 string_scanner: ^0.1.2
A version constraint that uses traditional syntax is a series of the following:
- The string
anyallows any version. This is equivalent to an empty version constraint, but is more explicit. Although
anyis allowed, we don’t recommend it.
- A concrete version number pins the dependency to only allow that exact version. Avoid using this when you can because it can cause version lock for your users and make it hard for them to use your package along with other packages that also depend on it.
- Allows the given version or any greater one. You’ll typically use this.
- Allows any version greater than the specified one but not that version itself.
- Allows any version lower than or equal to the specified one. You won’t typically use this.
- Allows any version lower than the specified one but not that version itself. This is what you’ll usually use because it lets you specify the upper version that you know does not work with your package (because it’s the first version to introduce some breaking change).
You can specify version parts as you want, and their ranges are intersected
together. For example,
'>=1.2.3 <2.0.0' allows any version from
2.0.0 itself. An easier way to express this range is
by using caret syntax, or
Pub supports two flavors of dependencies: regular dependencies and dev dependencies. Dev dependencies differ from regular dependencies in that dev dependencies of packages you depend on are ignored. Here’s an example:
transmogrify package uses the
test package in its tests and only
in its tests. If someone just wants to use
libraries—it doesn’t actually need
test. In this case, it specifies
test as a dev dependency. Its pubspec will have something like:
dev_dependencies: test: '>=0.5.0 <0.12.0'
Pub gets every package that your package depends on, and everything those
packages depend on, transitively. It also gets your package’s dev dependencies,
but it ignores the dev dependencies of any dependent packages. Pub only gets
your package’s dev dependencies. So when your package depends on
transmogrify it will get
transmogrify but not
The rule for deciding between a regular or dev dependency is simple: If
the dependency is imported from something in your
it needs to be a regular dependency. If it’s only imported from
example, etc. it can and should be a dev dependency.
Using dev dependencies makes dependency graphs smaller. That makes
faster, and makes it easier to find a set of package versions that satisfies all
You can use
dependency_overrides to temporarily override all references
to a dependency.
For example, perhaps you are updating a local copy of transmogrify, a published package. Transmogrify is used by other packages in your dependency graph, but you don’t want to clone each package locally and change each pubspec to test your local copy of transmogrify.
In this situation, you can override the dependency using
dependency_overrides to specify the directory holding the local
copy of the package.
The pubspec would look something like the following:
name: my_app dependencies: transmogrify: ^1.2.0 dependency_overrides: transmogrify: path: ../transmogrify_patch/
You can also use
dependency_overrides to specify a particular
version of a package:
name: my_app dependencies: transmogrify: ^1.2.0 dependency_overrides: transmogrify: '3.2.1'
Only the dependency overrides in a package’s own pubspec are considered during package resolution. Dependency overrides inside any depended-on packages are ignored.
As a result, if you publish a package to pub.dev, keep in mind that your package’s dependency overrides are ignored by all users of your package.
It’s important to actively manage your dependencies and ensure that your packages use the freshest versions possible. If any dependency is stale, then you might have not only a stale version of that package, but also stale versions of other packages in your dependency graph that depend on that package. These stale versions can have a negative impact on the stability, performance, and quality of apps.
We recommend the following best practices for package dependencies.
Specifying dependencies with version ranges such as
is a good practice because it allows the pub tool to
select newer versions of the package when they become available.
Also, it places an upper limit on the allowed version,
based on an assumption that packages use semantic versions,
where any version of path versioned
1.x is compatible,
but where a new version
2.x would be a major upgrade
that isn’t semantically compatible with
Depend on the latest stable package versions
dart pub upgrade to update to the latest package versions
that your pubspec allows.
To identify dependencies in your app or package that
aren’t on the latest stable versions,
dart pub outdated.
Test whenever you update package dependencies
If you run
dart pub upgrade without updating your pubspec,
the API should stay the same
and your code should run as before—but test to make sure.
If you modify the pubspec and update to a new major version,
then you might encounter breaking changes,
so you need to test even more thoroughly.
Verify the integrity of downloaded packages
When retrieving new dependencies, use the
option to ensure the extracted package content matches
the contents of the original archive.
Without modifying the lockfile,
this flag only resolves new dependencies if:
pubspec.lockis not missing
- The packages’ content hashes match