Lesson 20 min

Packages & Ecosystem — pub.dev

00:00 / 00:00

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 (.dart files)
  • 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:

MetricWhat It Means
LikesDeveloper thumbs-up count (community approval)
Pub PointsAutomated quality score (0–160): docs, analysis, license, etc.
PopularityHow many Flutter/Dart projects use it
SDK compatibilityWhich Dart/Flutter SDK versions it supports
ReadmeUsage instructions
ChangelogVersion history
Example tabCode 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.

yaml
name: 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

FieldPurpose
namePackage/project identifier (lowercase, underscores)
descriptionShort description (important for published packages)
versionYour project's version (semantic versioning)
environment.sdkWhich Dart SDK versions are compatible
dependenciesPackages needed at runtime
dev_dependenciesPackages needed only during development/testing

Version Constraints — Semantic Versioning

Dart uses semantic versioning (MAJOR.MINOR.PATCH):

PartMeaning
MAJORBreaking changes
MINORNew features, backward compatible
PATCHBug fixes, backward compatible

Constraint Syntax

yaml
dependencies: 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:

bash
dart 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:

bash
dart pub upgrade # Upgrade all packages dart pub upgrade http # Upgrade only 'http'

dart pub outdated

Shows which packages have newer versions available:

bash
dart 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:

bash
dart 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:

dart
import '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.:

dart
import '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

dart
import '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

dart
import '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:

dart
import '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

yaml
dependencies: 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):

dart
library 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:

yaml
name: 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:

bash
dart pub outdated --mode=null-safety

Summary

ConceptKey Takeaway
pub.devDart's official package registry
pubspec.yamlProject manifest — name, version, dependencies
dart pub getDownload packages listed in pubspec.yaml
dart pub upgradeUpgrade to latest allowed versions
dart pub outdatedSee which packages have updates
Caret ^Most common version constraint (same-major upgrades ok)
dependenciesRuntime packages — shipped with your app
dev_dependenciesDev-only packages — not shipped
Semantic versioningMAJOR.MINOR.PATCH
pubspec.lockLocks 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.

WhatsApp