Skip to content

Freezed: Supercharging Flutter Development

Flutter, Freezed, Macros, Dart, Immutability2 min read

Data management in Flutter applications can be a chore, especially when dealing with immutable data classes. But fear not, weary developers! The freezed package swoops in like a code-generating superhero, automating the creation of data classes, unions, and pattern matching. This translates to cleaner, more maintainable, and less error-prone code.

Why Freezed?

Before freezed, defining a proper data class involved writing boilerplate code for everything from constructors and properties to methods like toString, ==, and hashCode. Don't forget the essential copyWith method for immutably updating data, and optional JSON serialization/deserialization.

freezed eliminates this tedium. You simply define your data structure, and freezed generates the necessary code, allowing you to focus on the core logic that makes your app tick.

Getting Started

To use freezed in your Flutter project, follow these steps:

  1. Add dependencies: Include freezed_annotation and build_runner in your pubspec.yaml file. Optionally, include json_annotation for JSON functionality.

  2. Run the generator: Use flutter pub run build_runner build --delete-conflicting-outputs to trigger code generation.

Creating a Freezed Class

Let's see freezed in action. Here's an example of a data class representing a user:

2abstract class User with _$User {
3 const factory User({required String name, required int age}) = _User;

In this code, you define the User class with its properties and annotate it with @freezed. freezed generates methods like copyWith for updating the data and overrides methods like toString and ==.

Unions and Pattern Matching

freezed also allows creating unions, which represent different states your data can be in. For example, a user could be in a loading, loaded, or error state:

2abstract class UserState with _$UserState {
3 const factory UserState.loading() = _Loading;
4 const factory UserState.loaded(User user) = _Loaded;
5 const factory UserState.error(String message) = _Error;

Pattern matching with when or map lets you handle different states of your union:

2 loading: () => CircularProgressIndicator(),
3 loaded: (user) => Text(,
4 error: (message) => Text(message),

Benefits of Freezed

Using freezed offers several advantages:

  • Reduced boilerplate code: Focus on core logic, not repetitive code.
  • Improved code maintainability: Cleaner and more concise code.
  • Enhanced immutability: Ensures data integrity.
  • Simplified state management: Easier handling of data states with unions.

The Future of Freezed: Enter Macros

Now, let's get really exciting! The upcoming release of Macros in Dart has the potential to significantly change freezed. Macros are a powerful language feature that allows for code generation at compile time. This could potentially eliminate the need for the build_runner dependency and streamline the freezed experience even further. Imagine defining your data structures and having all the necessary code generated directly during compilation!

While the specifics of how Macros will impact freezed are yet to be seen, the possibilities are thrilling. It could lead to a more integrated and efficient development experience for Flutter developers using freezed.


By incorporating freezed into your Flutter development workflow, you can streamline data management, write more robust code, and save valuable development time. With its focus on code generation and immutability, freezed empowers you to build more efficient and maintainable Flutter applications. And who knows, with the arrival of Macros, the future of freezed might be even brighter!