Packages & pubspec.yaml
Almost no real Flutter app is built entirely from scratch — you'll routinely pull in third-party
packages for things like networking, local storage, and state management.
Everything about how your project is configured and what it depends on is controlled by a single
file at the project root: pubspec.yaml. This lesson covers it thoroughly, since
you'll be editing it constantly throughout real Flutter development.
pubspec.yaml: The Project's Manifest
Every Flutter project generated by flutter create comes with a
pubspec.yaml at its root. It's written in YAML and describes the project's identity
plus everything it depends on.
name: my_app
description: "A new Flutter project."
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: '>=3.0.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^1.0.6
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0
flutter:
uses-material-design: true
| Key | Purpose |
|---|---|
name | The package/project name, used internally for imports |
description | A short human-readable summary of the project |
version | Your app's version, in the form major.minor.patch+buildNumber |
dependencies | Packages your app needs at runtime, shipped in the final build |
dev_dependencies | Packages only needed during development, never shipped in the release build |
flutter | Flutter-specific configuration, including declared assets and fonts |
Adding a Package from pub.dev
pub.dev is the official package repository for Dart and Flutter — the equivalent
of npm for JavaScript or PyPI for Python. Adding a package to your project is a two-step process:
add a line under dependencies:, then tell Flutter to actually download it.
// Step 1: add the package and version constraint under dependencies:
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
// Step 2: fetch it
flutter pub get
flutter pub get reads pubspec.yaml, resolves compatible versions of
every dependency (and their own dependencies), downloads them, and generates/updates
pubspec.lock (more on that below). Once that finishes, you can import and use the
package in your Dart code:
import 'package:http/http.dart' as http;
void fetchData() async {
final response = await http.get(Uri.parse('https://example.com/data'));
print(response.body);
}
http is one of the most commonly used Flutter packages, for making network requests to REST APIs. It gets its own dedicated deep dive later in this track, in the HTTP Requests & APIs lesson — this is just a preview of the "add and use a package" workflow.Version Constraints: The Caret Syntax
That ^1.2.3 next to a package name is a version constraint written
using Dart's caret syntax, based on semantic versioning (semver:
major.minor.patch).
http: ^1.2.3
// Means: "any version from 1.2.3 up to, but NOT including, 2.0.0"
// Equivalent to: >=1.2.3 <2.0.0
The idea behind semantic versioning is that a major version bump (the first
number) signals breaking changes, while minor and patch bumps
are meant to be backward compatible. The caret constraint takes advantage of that convention:
it lets flutter pub get automatically pick up compatible bug fixes and new features
(1.3.0, 1.4.2, and so on) without ever silently jumping to a version that might break your code
(2.0.0).
dependencies vs dev_dependencies
It matters which section you add a package to. Packages under dependencies: are
bundled into your actual release build and available at runtime on a user's device. Packages
under dev_dependencies: are only available while you're developing — things like
testing frameworks and linters — and are stripped out entirely, never shipped to end users.
dependencies:
flutter:
sdk: flutter
http: ^1.2.0 // used by app code at runtime -> ships in the build
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^3.0.0 // only used during development -> never ships
import it to function, it belongs under dependencies:. If it's a tool you use while writing/testing the app, it belongs under dev_dependencies:.Declaring Assets in pubspec.yaml
Images, fonts, and other static files also have to be declared in pubspec.yaml,
under the flutter: section, before Flutter will bundle and let you use them.
flutter:
uses-material-design: true
assets:
- assets/images/logo.png
- assets/images/
fonts:
- family: Poppins
fonts:
- asset: assets/fonts/Poppins-Regular.ttf
- asset: assets/fonts/Poppins-Bold.ttf
weight: 700
Once declared, an image can be loaded in your widgets with Image.asset('assets/images/logo.png').
The full details of organizing an assets/ folder, handling different image
resolutions, and using custom fonts are covered in the upcoming Images & Assets lesson.
pubspec.lock: Reproducible Builds
Every time you run flutter pub get, Flutter writes (or updates) a
pubspec.lock file alongside pubspec.yaml. While pubspec.yaml
expresses a range of acceptable versions (like ^1.2.0),
pubspec.lock records the exact version that was actually resolved and
downloaded for every single dependency, direct and transitive.
pubspec.lock should be committed to version control for an application (packages/libraries handle this differently). Committing it guarantees that everyone on your team — and your CI pipeline — installs the exact same dependency versions, avoiding the classic "it works on my machine" problem caused by two developers silently resolving different compatible versions.Updating Packages: flutter pub upgrade
To update your dependencies to the newest versions still allowed by your version constraints in
pubspec.yaml (without editing that file by hand), use:
flutter pub upgrade
This re-resolves everything within your existing caret constraints and rewrites
pubspec.lock accordingly. If you deliberately want to move past a major version
boundary (say, from ^1.x to 2.x), you'll need to edit the constraint in
pubspec.yaml yourself first, since pub upgrade intentionally won't cross
that boundary on its own.