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.
pubspec.yaml structure
Section titled “pubspec.yaml structure”A minimal pubspec.yaml has five sections that map directly to package.json concepts:
name: my_appdescription: 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.pngname 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.
Version constraints
Section titled “Version constraints”Flutter uses the same caret semantics as npm:
^1.2.0means>=1.2.0 <2.0.0— compatible with the current major version.^0.4.3means>=0.4.3 <0.5.0— for pre-1.0 packages, the minor is the breaking boundary.anyaccepts all versions. Use it sparingly; it makes reproducible builds fragile.>=1.0.0 <2.0.0is the explicit form that^1.0.0expands to.
pubspec.lock pins the resolved versions, exactly like package-lock.json or yarn.lock. Always commit it.
Adding packages from the CLI
Section titled “Adding packages from the CLI”# 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 manuallyflutter pub get
# Upgrade dependencies within their constraintsflutter pub upgrade
# Check for outdated packagesflutter pub outdatedflutter 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.
Assets: no bundler import needed
Section titled “Assets: no bundler import needed”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”{ "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" }}name: my_appversion: 1.0.0+1environment: sdk: '>=3.3.0 <4.0.0'dependencies: flutter: sdk: flutter http: ^1.2.0dev_dependencies: flutter_test: sdk: flutter mocktail: ^1.0.4flutter: assets: - assets/images/ - assets/icons/app_icon.pngMaterial 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:
dart fix --apply --code=migrate_design_widgetsThat rewrites the imports and adds the packages to pubspec.yaml:
dependencies: flutter: sdk: flutter material_ui: ^1.2.0 cupertino_ui: ^1.0.0Nothing 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.