Watch the video (10 min)
On this page22 sections
  1. Prerequisites
  2. Connection With Previous Lectures
  3. Learning Objectives
  4. 1. What Is a Package?
  5. 2. Your Project Is Already a Package
  6. 3. package: Imports
  7. 4. package: vs Relative Imports
  8. 5. pub.dev — Where Packages Live
  9. 6. Adding a Package with dart pub add
  10. 7. .sum, .max, .min and .average
  11. 8. firstWhereOrNull
  12. 9. Empty Lists: max vs maxOrNull
  13. 10. A Real-World Example
  14. Code Examples
  15. Common Beginner Mistakes
  16. Best Practices
  17. Mini Challenge
  18. Practice Questions
  19. Practice Answers
  20. Quick Revision
  21. Key Takeaways
  22. What's Next?

Lecture 103 — Dart Packages

Category17 — Libraries & Packages
Lecture103 of 140
Estimated video length10 min
TargetDart 3.12.2
LevelIntermediate

Lists still have no .sum or .max, and dart: libraries can't help. Thousands of ready-made libraries are shared as packages — and one command adds them to your project.

Contents

Prerequisites · Connection · Objectives · Lesson · Code Examples · Common Mistakes · Best Practices · Mini Challenge · Practice Questions · Answers · Takeaways

Every output and error message in this lecture is real. Each one was produced by running the commands and code shown on Dart 3.12.2. dart pub add needs an internet connection.


Prerequisites

Students should already understand, from Lectures 002–102:

  • creating a project with dart create and running it with dart run (Lecture 002)
  • fold, reduce and the missing .sum (Lecture 044)
  • firstWhere on a list (Lecture 042)
  • extension methods (Lecture 069)
  • import, as, show and hide (Lecture 101)
  • splitting your code into library files (Lecture 102)

Connection With Previous Lectures

In Lecture 044, Dart refused marks.sum, and in Lecture 101 dart:math only gave us a max for two numbers:

dart
import 'dart:math';

void main() {
  var marks = [80, 75, 85];
  var total = marks.fold(0, (sum, mark) => sum + mark);
  print(marks.reduce(max));
  print(total);
}
output
85
240

It works, but every programmer in the world writes these same lines again and again. Someone has already written .sum and .max properly and shared them. We need a way to bring that shared code into our project.


Learning Objectives

By the end of this lecture you will be able to:

  • Explain what a package is and how it differs from a library
  • Recognize the parts of a package: pubspec.yaml and lib/
  • Find packages on pub.dev
  • Import with package: instead of a relative path
  • Add a package with dart pub add
  • Use .sum, .max, .min, .average and firstWhereOrNull from package:collection
  • Recognize the error messages Dart produces for common package mistakes

1. What Is a Package?

A package is a folder of Dart libraries with a pubspec.yaml file that gives it a name. The libraries others may use live in its lib/ folder.

Analogy — if a library is one book, a package is a boxed set: a label on the box (pubspec.yaml) and the books inside (lib/). You order the whole box, then read the books you need.


2. Your Project Is Already a Package

In Lecture 002, dart create built this layout:

bash
dart create marks_app
output
  pubspec.yaml
  bin/marks_app.dart
  lib/marks_app.dart
  test/marks_app_test.dart

It has a pubspec.yaml and a lib/ folder — so marks_app is a package. Its name comes from the first line of pubspec.yaml:

yaml
name: marks_app

bin/ holds the program you run; lib/ holds code to share. We will read the rest of pubspec.yaml in Lecture 104.


3. package: Imports

Open bin/marks_app.dart. Its first line imports the project's own lib/ file:

dart
import 'package:marks_app/marks_app.dart' as marks_app;

void main(List<String> arguments) {
  print('Hello world: ${marks_app.calculate()}!');
}
output
Hello world: 42!

Read package:marks_app/marks_app.dart as "in the package marks_app, open the file marks_app.dart inside its lib/ folder". You never write lib/ — package: always points there.


4. package: vs Relative Imports

A relative import gives a path from the current file, like 'bank_account.dart' in Lecture 057. From bin/ you could reach lib/ with ../lib/:

dart
import '../lib/marks_app.dart';

void main() {
  print(calculate());
}
output
42

It runs, but dart analyze objects:

output
info - bin/marks_app.dart:1:8 - Can't use a relative path to import a library in 'lib'. Try
fixing the relative path or changing the import to a 'package:' import. -
avoid_relative_lib_imports

The rule: from outside lib/ (bin/, test/), import lib/ files with package:. Inside lib/, relative imports between neighbours are fine.


5. pub.dev — Where Packages Live

pub.dev is Dart's official website for sharing packages. Search for a word like "collection" and each result shows:

  • likes — how many developers bookmarked it
  • pub points — a quality score out of 160 (documentation, formatting, analysis)
  • downloads — how widely it is used
  • a publisher badge — dart.dev means the Dart team itself maintains it

collection is published by dart.dev. It adds extra helpers for lists, sets and maps.


6. Adding a Package with dart pub add

Inside the project folder, run:

bash
dart pub add collection
output
Resolving dependencies...
Downloading packages...
  collection 1.19.1 (from transitive dependency to direct dependency)
Changed 1 dependency!

The tools dart create installed already used collection behind the scenes — that is the "transitive dependency". Now our own code depends on it directly. A new package would simply show as + name version. pubspec.yaml gained one line:

yaml
dependencies:
  collection: ^1.19.1

We will explain ^1.19.1 and pubspec.lock in Lectures 104–105.


7. .sum, .max, .min and .average

Import the package's main library, and lists of numbers gain new getters:

dart
import 'package:collection/collection.dart';

void main() {
  var marks = [80, 75, 85];
  print(marks.sum);
  print(marks.max);
  print(marks.min);
  print(marks.average);
}
output
240
85
75
80.0

These are extension getters (Lecture 069) written by the Dart team. .average is always a double.


8. firstWhereOrNull

firstWhere crashes when nothing matches:

dart
void main() {
  var names = ['Ali', 'Sara', 'Zayan'];
  print(names.firstWhere((n) => n.startsWith('H')));
}
output
Unhandled exception:
Bad state: No element

firstWhereOrNull from collection returns null instead, so ?? can supply a fallback:

dart
import 'package:collection/collection.dart';

void main() {
  var names = ['Ali', 'Sara', 'Zayan'];
  print(names.firstWhereOrNull((n) => n.startsWith('S')));
  print(names.firstWhereOrNull((n) => n.startsWith('H')) ?? 'nobody');
}
output
Sara
nobody

9. Empty Lists: max vs maxOrNull

.sum of an empty list is 0, but .max has no answer and throws. maxOrNull and minOrNull return null instead:

dart
import 'package:collection/collection.dart';

void main() {
  var marks = <int>[];
  print(marks.sum);
  print(marks.maxOrNull);
}
output
0
null

Calling marks.max here gives Bad state: No element, just like reduce in Lecture 044.


10. A Real-World Example

A class summary using the project's package:collection dependency:

dart
import 'package:collection/collection.dart';

void main() {
  var marks = {'Ali': 72, 'Sara': 95, 'Zayan': 44, 'Hina': 88};

  var total = marks.values.sum;
  var average = marks.values.average;
  var best = marks.values.max;
  var topStudent = marks.keys.firstWhereOrNull((n) => marks[n] == best);
  var failing = marks.keys.firstWhereOrNull((n) => marks[n]! < 50);

  print('Total: $total, Average: $average');
  print('Top: $topStudent with $best');
  print('Needs help: ${failing ?? 'no one'}');
}
output
Total: 299, Average: 74.75
Top: Sara with 95
Needs help: Zayan

No fold, no reduce, no dart:math — one import, and the code says what it means.


Code Examples

Run each example from the bin/ folder of a project where you ran dart pub add collection.

Example 1 — Sum

dart
import 'package:collection/collection.dart';

void main() {
  var scores = [12, 30, 8];
  print('Sum: ${scores.sum}');
}
output
Sum: 50

Example 2 — Max and Min

dart
import 'package:collection/collection.dart';

void main() {
  var ages = [21, 6, 18];
  print('Oldest: ${ages.max}');
  print('Youngest: ${ages.min}');
}
output
Oldest: 21
Youngest: 6

Example 3 — Average

dart
import 'package:collection/collection.dart';

void main() {
  var steps = [4000, 6500, 5500];
  print(steps.average);
}
output
5333.333333333333

Example 4 — firstWhereOrNull Finds a Match

dart
import 'package:collection/collection.dart';

void main() {
  var cities = ['Lahore', 'Karachi', 'Quetta'];
  print(cities.firstWhereOrNull((c) => c.length > 6));
}
output
Karachi

Example 5 — No Match, Safe Fallback

dart
import 'package:collection/collection.dart';

void main() {
  var cities = ['Lahore', 'Karachi', 'Quetta'];
  var city = cities.firstWhereOrNull((c) => c.startsWith('Z'));
  print(city ?? 'not found');
}
output
not found

Example 6 — A package: Import of Your Own Code

dart
import 'package:marks_app/marks_app.dart';

void main() {
  print('Answer: ${calculate()}');
}
output
Answer: 42

Example 7 — Student Marks

dart
import 'package:collection/collection.dart';

void main() {
  var marks = [55, 91, 78, 66];
  print('Total: ${marks.sum}');
  print('Average: ${marks.average}');
  print('Gap: ${marks.max - marks.min}');
}
output
Total: 290
Average: 72.5
Gap: 36

How it works

  1. .sum replaces fold(0, (sum, mark) => sum + mark).
  2. .max and .min replace reduce(max) and reduce(min).

Example 8 — Shopping Total

dart
import 'package:collection/collection.dart';

void main() {
  var cart = {'Notebook': 500, 'Pen': 50, 'Bag': 1500};
  print('Items: ${cart.length}');
  print('Total: ${cart.values.sum}');
  print('Priciest: ${cart.values.max}');
}
output
Items: 3
Total: 2050
Priciest: 1500

How it works

  1. cart.values is an Iterable<int>; the getters work on any iterable of numbers, not only lists.

Example 9 — Bank Balance

dart
import 'package:collection/collection.dart';

void main() {
  var history = [1000, -200, 500, -50];
  var balance = history.sum;
  var bigWithdrawal = history.firstWhereOrNull((t) => t < -100);
  print('Balance: $balance');
  print('First big withdrawal: ${bigWithdrawal ?? 'none'}');
}
output
Balance: 1250
First big withdrawal: -200

How it works

  1. Deposits are positive and withdrawals negative, so .sum is the balance.
  2. firstWhereOrNull finds the first amount below -100, or null.

Example 10 — Temperatures

dart
import 'package:collection/collection.dart';

void main() {
  var week = [29.5, 31.0, 30.5, 32.0, 28.0];
  print('Hottest: ${week.max}');
  print('Average: ${week.average.toStringAsFixed(1)}');
}
output
Hottest: 32.0
Average: 30.2

How it works

  1. The getters work on double lists too; .max stays a double.
  2. toStringAsFixed(1) rounds 30.2 for display.

Common Beginner Mistakes

1. Importing a package you never added

dart
// import 'package:intl/intl.dart'; // ✗ intl is not in pubspec.yaml
output
Error: Couldn't resolve the package 'intl' in 'package:intl/intl.dart'.

Run dart pub add intl first.

2. Running a package import outside a project

A single file in a folder with no pubspec.yaml has no packages, so even collection fails:

output
Error: Couldn't resolve the package 'collection' in 'package:collection/collection.dart'.

Put the file in a project's bin/ folder.

3. Misspelling the package name

bash
dart pub add colection
output
Because marks_app depends on colection any which doesn't exist (could not find package
colection at https://pub.dev), version solving failed.

4. Forgetting the import

dart
void main() {
  var marks = [80, 75];
  // print(marks.sum); // ✗ no import 'package:collection/collection.dart'
}
output
Error: The getter 'sum' isn't defined for the type 'List<int>'.

Adding a package does not import it — every file that uses it needs the import line.

5. Writing lib/ in a package: import

package:marks_app/lib/marks_app.dart is wrong. package: already means "inside lib/": write package:marks_app/marks_app.dart.

6. Calling .max on a list that may be empty

It throws Bad state: No element. Use maxOrNull with ??.


Best Practices

  • Check dart: libraries first; add a package only when they can't do the job.
  • Prefer well-known packages: a verified publisher, high pub points, recent updates.
  • Add packages with dart pub add, not by hand-editing pubspec.yaml.
  • Use package: imports from bin/ and test/ into lib/.
  • Put dart: imports first, then package: imports, then relative ones.
  • Use firstWhereOrNull and maxOrNull when "nothing found" is a normal result.

Mini Challenge

Zayan's quiz scores are [7, 9, 4, 10, 8]. Using package:collection, print the total, the best score, and the first score below 5.

Your program should print exactly:

output
Total: 38
Best: 10
First low score: 4

Try it yourself before opening the solution.

Show solution
dart
import 'package:collection/collection.dart';

void main() {
  var scores = [7, 9, 4, 10, 8];
  print('Total: ${scores.sum}');
  print('Best: ${scores.max}');
  print('First low score: ${scores.firstWhereOrNull((s) => s < 5)}');
}
output
Total: 38
Best: 10
First low score: 4

How it works

  1. .sum and .max come from the package's extensions on numbers.
  2. firstWhereOrNull returns the first match, 4.

Practice Questions

Work through these in order — they run from beginner to application to challenge. Run them inside a project that has collection added.

Beginner

  1. Print the sum of [3, 6, 9] with .sum.
  2. Print the largest and smallest of [45, 12, 78, 33].
  3. Write the import line for package:collection, and the command that adds it to a project.

Application

  1. Print the average of [60, 70, 95].

  2. From ['Ali', 'Sara', 'Hina'], print the first name containing 'n', or none.

  3. From [15, 22, 9], print the first number above 30, or none.

  4. Print maxOrNull of an empty <int>[], followed by .sum of the same list.

  5. This file in bin/ imports lib/marks_app.dart the discouraged way. Rewrite the import:

    dart
    import '../lib/marks_app.dart';

Challenge

  1. For the prices {'Pen': 50, 'Book': 450, 'Bag': 1500}, print Total: 2000 and Average: 666.67.
  2. Sara's deposits are [2000, 500, 750] and her withdrawals [300, 1200]. Print her balance and her biggest single withdrawal.

Practice Answers

Question 1 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  print([3, 6, 9].sum);
}
output
18

Question 2 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  var values = [45, 12, 78, 33];
  print(values.max);
  print(values.min);
}
output
78
12

Question 3 — Solution

dart
import 'package:collection/collection.dart';
bash
dart pub add collection

Question 4 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  print([60, 70, 95].average);
}
output
75.0

Question 5 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  var names = ['Ali', 'Sara', 'Hina'];
  print(names.firstWhereOrNull((n) => n.contains('n')) ?? 'none');
}
output
Hina

Question 6 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  var numbers = [15, 22, 9];
  print(numbers.firstWhereOrNull((n) => n > 30) ?? 'none');
}
output
none

Question 7 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  var empty = <int>[];
  print(empty.maxOrNull);
  print(empty.sum);
}
output
null
0

Question 8 — Solution

dart
import 'package:marks_app/marks_app.dart';

package: points into lib/ from anywhere in the project, and dart analyze stops warning.

Question 9 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  var prices = {'Pen': 50, 'Book': 450, 'Bag': 1500};
  print('Total: ${prices.values.sum}');
  print('Average: ${prices.values.average.toStringAsFixed(2)}');
}
output
Total: 2000
Average: 666.67

Question 10 — Solution

dart
import 'package:collection/collection.dart';

void main() {
  var deposits = [2000, 500, 750];
  var withdrawals = [300, 1200];
  print('Balance: ${deposits.sum - withdrawals.sum}');
  print('Biggest withdrawal: ${withdrawals.max}');
}
output
Balance: 1750
Biggest withdrawal: 1200

Quick Revision

  1. What two things make a folder a package?
  2. Is a project made by dart create a package?
  3. Which folder does package:name/file.dart point into?
  4. Where do you find shared Dart packages?
  5. Which command adds collection to a project?
  6. Does adding a package import it into every file?
  7. What does firstWhereOrNull return when nothing matches?
  8. Why use maxOrNull instead of max?

Key Takeaways

  • A package is a pubspec.yaml plus libraries in lib/; every dart create project is one.
  • package:name/file.dart imports lib/file.dart of package name.
  • From bin/ and test/, import lib/ files with package:, not ../lib/.
  • pub.dev hosts shared packages; check likes, pub points and the publisher.
  • dart pub add name downloads a package and records it in pubspec.yaml.
  • Each file that uses a package still needs its import line.
  • package:collection adds .sum, .max, .min, .average, firstWhereOrNull and maxOrNull.

What's Next?

Lecture 104 — pubspec.yaml. dart pub add quietly wrote a line into pubspec.yaml. Next we will read that file line by line — the package name, the SDK version, and what collection: ^1.19.1 really promises.


Video lecture

Subscribe
Placeholder video — the real recording isn't linked yet.