Freezed: Immutable State Without Boilerplate
Freezed is a Dart code generator that writes your immutable data classes for you. You define the shape, and it generates constructors, `copyWith`, and equality checks. Use it for model classes and to represent distinct states.
WHY IT EXISTS Writing immutable classes in Dart is verbose. For every model, you must manually override toString, operator==, hashCode, and implement a copyWith method. This boilerplate is repetitive, error-prone, and clutters your core logic.
THE MENTAL MODEL Think of Freezed as a blueprint-to-factory machine. You provide a simple blueprint—a class with a factory constructor—and the machine (a code generator) builds the entire, fully-functional, immutable class for you, complete with all the necessary methods.
HOW IT WORKS You define a Dart class using the @freezed annotation and a part file directive. Inside, you write one or more factory constructors that define the shape of your data. You then run the build_runner command in your terminal. This process reads your class definition and generates a .freezed.dart file containing the full implementation of an immutable class, including properties, a private constructor, the copyWith method, and equality checks.
WHEN TO USE IT Use Freezed for any data class that should be immutable, especially for model classes representing API responses. It excels in state management (e.g., with Riverpod or BLoC) by creating union types. This allows you to define a state as one of several possibilities, like AuthState.loading(), AuthState.authenticated(User user), or AuthState.error(String msg), forcing you to handle all cases in the UI and preventing bugs.
WHEN NOT TO USE IT Avoid Freezed if you genuinely need a mutable class where properties can be changed directly after creation. While you can configure Freezed to produce mutable classes, its primary benefit is enforcing immutability. For simple, temporary data holders that don't need cloning or equality checks, a plain Dart class is sufficient and avoids the build step.
ONE CANONICAL EXAMPLE To create an immutable User, you define a file user.dart starting with part 'user.freezed.dart';. The class is @freezed class User with _$User { const factory User({required String id, required String name}) = _User; }. After running the code generator, you can create an instance: final user1 = User(id: '1', name: 'Alice');. To "update" the name, you create a new instance: final user2 = user1.copyWith(name: 'Alicia');. The original user1 object remains unchanged.
Read the original → pub.dev
Get five bites like this every day.
Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.