Skip to content
AgileLogics
5 min read

Class Modifiers

Prerequisites: Sealed classes and exhaustive switching, Interfaces and implements

By default, any Dart class can be created, extended, and implemented by anyone. Dart 3's class modifiers let a library author restrict that — which matters most when publishing packages others depend on.

The modifiers

Modifier Outside the library, the class can be...
(none) created, extended, and implemented
abstract extended and implemented, but not created directly
base created and extended, but not implemented
interface created and implemented, but not extended
final created only — not extended or implemented
sealed none of these — and switches over it are exhaustive
mixin class used as both a class and a mixin

These restrictions apply outside the library (file) where the class is declared; inside it, you can still extend and implement freely. That's why a sealed class's subclasses must live in the same file.

Why restrict?

// In your package:
final class Money {
  final int cents;
  const Money(this.cents);
}

interface class PaymentGateway {
  Future<bool> charge(int cents) async => true;
}

base class Repository {
  void save() => print('saved');
}
  • final class Money — nobody can subclass Money and change its behavior, so your code can trust any Money value. You're also free to add members later without breaking anyone.
  • interface class PaymentGateway — users implement it (for example, with a fake in tests), but can't inherit from your implementation and depend on its internals.
  • base class Repository — subclasses must inherit your implementation, which guarantees your internal logic always runs.

A user of the package who tries class MyMoney extends Money {} gets a compile error explaining that Money can't be extended outside its library.

Modifiers can be combined: abstract interface class is the Dart 3 way to declare a pure interface.

Do you need them?

In application code, rarely — except sealed, which is valuable everywhere for exhaustive switching. In packages, they let you evolve your API safely. Choose the most restrictive modifier that still allows what your users need; you can always loosen it later without breaking anyone, but not the other way round.