Packages & Ecosystem — pub.dev
Packages & Ecosystem — pub.dev
One of Dart's greatest strengths is its rich package ecosystem. Instead of writing everything from scratch, you can leverage thousands of community-built packages. In this lesson, you'll learn how to find, install, and use packages — and even create your own.
What Is a Package?
A package is a reusable module of Dart code that you can add to your project. Packages can include:
- Dart libraries (
.dartfiles) - Assets (images, fonts, data files)
- Platform-specific code (for Flutter packages)
- Executable tools
Packages solve a fundamental problem: don't reinvent the wheel. Need to make HTTP requests? There's a package. Need to format dates? There's a package. Need to generate UUIDs? There's a package.
pub.dev — Dart's Package Registry
pub.dev is the official repository for Dart and Flutter packages. Every public Dart package lives here.
What You See on pub.dev
When you visit a package page, you'll find:
| Metric | What It Means |
|---|---|
| Likes | Developer thumbs-up count (community approval) |
| Pub Points | Automated quality score (0–160): docs, analysis, license, etc. |
| Popularity | How many Flutter/Dart projects use it |
| SDK compatibility | Which Dart/Flutter SDK versions it supports |
| Readme | Usage instructions |
| Changelog | Version history |
| Example tab | Code examples |
[!TIP] When evaluating a package, look for: high pub points (> 120), recent updates, good documentation, and active issue resolution on GitHub.
pubspec.yaml — Project Manifest
Every Dart project has a pubspec.yaml file — the project's configuration file. It describes your project and its dependencies.
yamlname: my_dart_app description: A sample Dart application. version: 1.0.0 # Dart SDK version constraint environment: sdk: '>=3.0.0 <4.0.0' # Runtime dependencies — included in production dependencies: http: ^1.2.0 intl: ^0.19.0 uuid: ^4.3.3 equatable: ^2.0.5 # Development-only dependencies — NOT included in production dev_dependencies: test: ^1.24.0 mockito: ^5.4.4 lints: ^3.0.0
Key Fields Explained
| Field | Purpose |
|---|---|
name | Package/project identifier (lowercase, underscores) |
description | Short description (important for published packages) |
version | Your project's version (semantic versioning) |
environment.sdk | Which Dart SDK versions are compatible |
dependencies | Packages needed at runtime |
dev_dependencies | Packages needed only during development/testing |
Version Constraints — Semantic Versioning
Dart uses semantic versioning (MAJOR.MINOR.PATCH):
| Part | Meaning |
|---|---|
MAJOR | Breaking changes |
MINOR | New features, backward compatible |
PATCH | Bug fixes, backward compatible |
Constraint Syntax
yamldependencies: http: '1.2.0' # Exactly version 1.2.0 http: '>=1.0.0' # 1.0.0 or later (any version) http: '>=1.0.0 <2.0.0' # Any 1.x version http: '^1.2.0' # >=1.2.0 <2.0.0 (caret — most common) http: any # Any version (avoid this)
The caret (^) is most commonly used — it allows upgrades within the same major version, which should be backward compatible.
pub Commands
dart pub get
Downloads all packages listed in pubspec.yaml and creates pubspec.lock:
bashdart pub get
The pubspec.lock file records the exact versions resolved. Always commit this file to version control — it ensures everyone on your team uses identical package versions.
dart pub upgrade
Upgrades packages to the latest versions allowed by your constraints:
bashdart pub upgrade # Upgrade all packages dart pub upgrade http # Upgrade only 'http'
dart pub outdated
Shows which packages have newer versions available:
bashdart pub outdated
Output example:
Package Name Current Upgradable Resolvable Latest
http 1.1.0 1.2.1 1.2.1 1.2.1
intl 0.18.0 0.19.0 0.19.0 0.19.0
dart pub add
Quickly add a dependency without manually editing pubspec.yaml:
bashdart pub add http # Add to dependencies dart pub add --dev test # Add to dev_dependencies
Popular Dart Packages
1. http — HTTP Requests
The standard HTTP client for Dart:
dartimport 'package:http/http.dart' as http; import 'dart:convert'; Future<void> fetchUsers() async { final url = Uri.parse('https://jsonplaceholder.typicode.com/users'); final response = await http.get(url); if (response.statusCode == 200) { final List data = jsonDecode(response.body); for (var user in data) { print('\${user['name']} — \${user['email']}'); } } else { print('Request failed: \${response.statusCode}'); } }
2. dio — Advanced HTTP Client
dio is more feature-rich than http — it supports interceptors, request cancellation, FormData, etc.:
dartimport 'package:dio/dio.dart'; final dio = Dio(); Future<void> fetchPost(int id) async { try { final response = await dio.get('https://jsonplaceholder.typicode.com/posts/\$id'); print(response.data['title']); } on DioException catch (e) { print('Dio error: \${e.message}'); } }
3. intl — Internationalization & Date Formatting
dartimport 'package:intl/intl.dart'; void main() { final now = DateTime.now(); // Date formatting print(DateFormat('MMMM d, yyyy').format(now)); // July 15, 2026 print(DateFormat('dd/MM/yyyy').format(now)); // 15/07/2026 print(DateFormat.yMMMEd().format(now)); // Tue, Jul 15, 2026 // Number formatting final formatter = NumberFormat.currency(locale: 'en_US', symbol: '\$'); print(formatter.format(1234567.89)); // \$1,234,567.89 // Relative time print(DateFormat.jm().format(now)); // 1:30 PM }
4. uuid — Generating Unique IDs
dartimport 'package:uuid/uuid.dart'; void main() { const uuid = Uuid(); print(uuid.v4()); // e.g. 550e8400-e29b-41d4-a716-446655440000 print(uuid.v4()); // Different each time // Use as database IDs, session tokens, etc. final userId = uuid.v4(); final sessionId = uuid.v4(); print('User: \$userId'); print('Session: \$sessionId'); }
5. equatable — Value Equality for Classes
By default, Dart objects are compared by reference. equatable makes classes compare by value:
dartimport 'package:equatable/equatable.dart'; class User extends Equatable { final int id; final String name; const User({required this.id, required this.name}); List<Object?> get props => [id, name]; } void main() { final u1 = User(id: 1, name: 'Alice'); final u2 = User(id: 1, name: 'Alice'); final u3 = User(id: 2, name: 'Bob'); print(u1 == u2); // true ✅ (same id and name) print(u1 == u3); // false ✅ }
Dev vs Runtime Dependencies
yamldependencies: http: ^1.2.0 # ✅ Needed at runtime — ships with your app dev_dependencies: test: ^1.24.0 # ✅ Only for development — NOT shipped mockito: ^5.4.4 # ✅ Only for tests — NOT shipped lints: ^3.0.0 # ✅ Static analysis — NOT shipped
[!IMPORTANT]
Always put test frameworks, mocking libraries, and linters in dev_dependencies. This keeps your production build lean and avoids shipping unnecessary code.
Creating Your Own Package
Here's the structure of a simple Dart package:
my_utils/
├── lib/
│ ├── my_utils.dart ← Main library file (exports)
│ └── src/
│ ├── string_utils.dart ← Implementation files
│ └── math_utils.dart
├── test/
│ └── my_utils_test.dart
├── example/
│ └── example.dart
├── pubspec.yaml
├── README.md
├── CHANGELOG.md
└── LICENSE
lib/my_utils.dart (the public API):
dartlibrary my_utils; export 'src/string_utils.dart'; export 'src/math_utils.dart';
lib/src/string_utils.dart:
dart/// Capitalizes the first letter of a string. String capitalize(String s) { if (s.isEmpty) return s; return s[0].toUpperCase() + s.substring(1); } /// Reverses a string. String reverse(String s) => s.split('').reversed.join(); /// Checks if a string is a palindrome. bool isPalindrome(String s) { final cleaned = s.toLowerCase().replaceAll(RegExp(r'[^a-z0-9]'), ''); return cleaned == reverse(cleaned); }
pubspec.yaml for the package:
yamlname: my_utils description: Utility functions for string and math operations. version: 0.1.0 environment: sdk: '>=3.0.0 <4.0.0' dev_dependencies: test: ^1.24.0
Analyzing a Package Before Using It
Before adding a package, run a quick checklist:
✅ High pub points (120+)
✅ Recently updated (within 6 months)
✅ Has a README with clear examples
✅ Dart 3 compatible (null-safe)
✅ Active GitHub repository
✅ Reasonable number of open issues
✅ Used by reputable projects
You can also check compatibility:
bashdart pub outdated --mode=null-safety
Summary
| Concept | Key Takeaway |
|---|---|
| pub.dev | Dart's official package registry |
| pubspec.yaml | Project manifest — name, version, dependencies |
dart pub get | Download packages listed in pubspec.yaml |
dart pub upgrade | Upgrade to latest allowed versions |
dart pub outdated | See which packages have updates |
Caret ^ | Most common version constraint (same-major upgrades ok) |
dependencies | Runtime packages — shipped with your app |
dev_dependencies | Dev-only packages — not shipped |
| Semantic versioning | MAJOR.MINOR.PATCH |
| pubspec.lock | Locks exact versions — always commit this |
[!TIP] Resist the urge to add a package for every small task. Evaluate whether the package is worth the added complexity and maintenance burden. A well-chosen package is a huge productivity win; a poorly-maintained one can become a liability.
In the next lesson, we'll learn how to write Unit Tests in Dart to ensure your code is correct and maintainable.