Dart Sealed Classes vs Abstract Classes – What to Use and When?

Introduction

Dart 3 introduced sealed classes — a powerful new feature that enables more robust control over class hierarchies and pattern matching. If you’re coming from traditional Dart or Java/OOP backgrounds, you’re probably familiar with abstract classes. But now, with sealed classes in play, the question arises:

Should I use a sealed class or an abstract class in Dart?

In this in-depth guide, we’ll explore the difference between Dart sealed classes vs abstract classes, when to use each, how they work under the hood, and why sealed classes are revolutionizing Dart’s type system — especially in Flutter and backend Dart development.

What Is an Abstract Class in Dart?

An abstract class in Dart defines a class that cannot be instantiated directly. It’s commonly used as a base class to define interfaces and share functionality between subclasses.

Example:

abstract class Animal {
  void speak();
}

class Dog extends Animal {
  @override
  void speak() => print("Woof!");
}

Key Features:

  • Cannot be instantiated
  • Can contain abstract and non-abstract methods
  • Subclasses must implement abstract methods
  • Not type-restrictive (any class can extend)

What Is a Sealed Class in Dart?

A sealed class is a class that restricts which classes can extend or implement it. Introduced in Dart 3, it provides exhaustive control over class hierarchies, making it ideal for pattern matching, state modeling, and domain-driven design.

Read : How to Debounce a Function in Dart?

Example:

sealed class Shape {}

class Circle extends Shape {}
class Rectangle extends Shape {}

Here, only classes in the same file can extend Shape. This enables Dart to know all possible subclasses at compile time, which is essential for switch expressions and exhaustive pattern matching.

Sealed Classes vs Abstract Classes – Comparison Table

FeatureAbstract ClassSealed Class
Can be instantiated❌ No❌ No
Can have implementations✅ Yes✅ Yes
Restricts subclassing❌ No✅ Yes (file-scope only)
Ideal for switch/pattern match❌ No (not exhaustive)✅ Yes (fully exhaustive)
Open hierarchy✅ Yes❌ No (sealed to same file)
Use caseShared logic/interfaceFixed state modeling, unions
Introduced inDart 1.x+Dart 3.x

Real-World Use Case for Sealed Class

Let’s say you’re building a state model for a Flutter BLoC or Cubit:

sealed class AuthState {}

class AuthInitial extends AuthState {}
class AuthLoading extends AuthState {}
class AuthSuccess extends AuthState {}
class AuthError extends AuthState {
  final String message;
  AuthError(this.message);
}

Now, in your widget or logic layer, you can pattern match with complete confidence:

void handleAuthState(AuthState state) {
switch (state) {
case AuthInitial():
// Show welcome screen
break;
case AuthLoading():
// Show loading spinner
break;
case AuthSuccess():
// Navigate to home
break;
case AuthError(:final message):
print("Login failed: $message");
break;
}
}

Because the class is sealed, Dart knows no other subclasses can exist, and this switch is exhaustive — which means safer, bug-free code.

Read Articles : Mastering Extension Methods in Dart – Cleaner Code with Real World Use Cases

When to Use Abstract Classes

Use an abstract class when:

  • You want to define a shared interface or contract
  • You don’t need subclass restriction
  • Your hierarchy spans multiple files or packages
  • You need default implementations (e.g., utility methods)

Example:

abstract class Logger {
  void log(String message);
  
  void logError(String message) {
    log("ERROR: $message");
  }
}

When to Use Sealed Classes

Use a sealed class when:

  • You want to model fixed sets of types
  • You’re using switch statements with pattern matching
  • You want to prevent external classes from extending the base class
  • You’re designing a state system, event model, or result type

Limitations of Sealed Classes

  • Only classes in the same file can extend/implement them
  • Not supported in older Dart versions
  • Cannot be used across modules/libraries
  • Not meant for reusability across features like abstract classes

Read Articles : How to Use Isolates for CPU-Intensive Tasks in Dart?

FAQ – Dart Sealed vs Abstract Classes

What’s the difference between abstract and sealed classes in Dart?

Abstract classes define structure but allow open extension. Sealed classes restrict subclassing and allow pattern matching.

Can sealed classes have methods?

Yes. Sealed classes can contain both methods and fields, just like abstract classes.

Are sealed classes faster or better for performance?

Not necessarily faster, but they enable safer and more expressive code, especially with pattern matching.

Can I use sealed classes in Flutter projects?

Absolutely. They’re perfect for modeling State, Events, or Navigation Routes in Flutter apps.

Do sealed classes replace abstract classes?

No — they solve different problems. Use sealed for fixed hierarchies and abstract for open contracts.

Understanding the difference between Dart sealed classes vs abstract classes is essential for writing clean, safe, and maintainable Dart code — especially in large apps and frameworks like Flutter.

  • Use abstract classes for shared behavior and reusability across modules.
  • Use sealed classes when your type hierarchy should be restricted and exhaustive — especially when used with pattern matching.

If you’re building state-driven UIs, domain models, or functional-style logic in Dart 3 or Flutter, sealed classes are a powerful new tool worth mastering.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More