Skip to content

pub & pubspec.yaml

In React you manage dependencies through npm and package.json. In Flutter, pub is the package manager and pubspec.yaml is the project manifest. The registry is pub.dev instead of npmjs.com, but the workflow is the same: find a package, add it to the manifest, fetch it, import it in code.

A minimal pubspec.yaml has five sections that map directly to package.json concepts:

name: my_app
description: A Flutter application.
version: 1.0.0+1
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
dev_dependencies:
flutter_test:
sdk: flutter
mocktail: ^1.0.4
flutter:
assets:
- assets/images/
- assets/icons/app_icon.png

name and description are identical to package.json. version uses a major.minor.patch+build format — the +1 is a build number used by app stores and has no npm equivalent. environment.sdk pins the Dart SDK range (no Node engine field in package.json does this by default, but it is the same intent). dependencies and dev_dependencies mirror npm’s dependencies and devDependencies. The flutter: block is unique — it is where you register assets so the framework can bundle them.

Flutter uses the same caret semantics as npm:

  • ^1.2.0 means >=1.2.0 <2.0.0 — compatible with the current major version.
  • ^0.4.3 means >=0.4.3 <0.5.0 — for pre-1.0 packages, the minor is the breaking boundary.
  • any accepts all versions. Use it sparingly; it makes reproducible builds fragile.
  • >=1.0.0 <2.0.0 is the explicit form that ^1.0.0 expands to.

pubspec.lock pins the resolved versions, exactly like package-lock.json or yarn.lock. Always commit it.

Terminal window
# Add a runtime dependency (like npm install http)
flutter pub add http
# Add a dev dependency (like npm install --save-dev mocktail)
flutter pub add --dev mocktail
# Fetch all dependencies after editing pubspec.yaml manually
flutter pub get
# Upgrade dependencies within their constraints
flutter pub upgrade
# Check for outdated packages
flutter pub outdated

flutter pub add http does two things in one step: it edits pubspec.yaml to add the entry under dependencies, then runs pub get to download the package. There is no separate “save” flag — the manifest is always updated.

In a React/Vite project you import images directly in JavaScript:

import logo from './assets/logo.svg';

Vite handles the bundling. In Flutter there is no bundler import. Instead, you declare asset paths in pubspec.yaml under flutter: assets:, and then reference them by string path in Dart:

Image.asset('assets/images/logo.png')

You can declare a whole directory (assets/images/) to include every file inside it, or list individual files for fine-grained control. Flutter will bundle exactly what you declare and nothing else.

Side-by-side: package.json vs pubspec.yaml

Section titled “Side-by-side: package.json vs pubspec.yaml”
React
{
"name": "my-app",
"version": "1.0.0",
"dependencies": {
"react": "^18.2.0",
"axios": "^1.6.0"
},
"devDependencies": {
"@testing-library/react": "^14.0.0",
"vite": "^5.0.0"
},
"scripts": {
"dev": "vite",
"build": "vite build",
"test": "jest"
}
}
Flutter
name: my_app
version: 1.0.0+1
environment:
sdk: '>=3.3.0 <4.0.0'
dependencies:
flutter:
sdk: flutter
http: ^1.2.0
dev_dependencies:
flutter_test:
sdk: flutter
mocktail: ^1.0.4
flutter:
assets:
- assets/images/
- assets/icons/app_icon.png

Material and Cupertino are becoming packages

Section titled “Material and Cupertino are becoming packages”

Every example in this course starts with the same line:

import 'package:flutter/material.dart';

That import comes from the SDK itself, not from pub.dev — which is why you never saw Material listed in dependencies. Flutter 3.47 starts changing that. Material and Cupertino now also ship as standalone pub.dev packages, material_ui and cupertino_ui, each versioned and released independently of the SDK (material_ui on pub.dev).

For a React developer the motivation is familiar: it is the difference between a widget library baked into the runtime and one you install like @mui/material. Decoupling lets the design system ship fixes and new components without waiting for an SDK release, and lets your app pin a version.

The SDK imports still work today. The in-SDK copies are scheduled for formal deprecation in the November stable release, and Flutter ships a migration for it:

Terminal window
dart fix --apply --code=migrate_design_widgets

That rewrites the imports and adds the packages to pubspec.yaml:

dependencies:
flutter:
sdk: flutter
material_ui: ^1.2.0
cupertino_ui: ^1.0.0

Nothing in this course requires the migration yet — the SDK import is still correct on 3.47. Run dart fix when you start a new project, and read the deprecation note in the release you are on before migrating an existing app.

What is the pubspec.yaml equivalent of npm's devDependencies?
What does the version constraint "^1.2.0" mean in pubspec.yaml?
How do you add a package AND update pubspec.yaml in one command?
Where do you declare image assets in a Flutter project?