App Development
2026-03-27
5 min read

Mastering Dart Tear-offs: Why Constructor.new is the Future of Flutter State Management

Stop wrapping your Riverpod Notifiers in unnecessary anonymous functions. Learn how the .new syntax (Constructor Tear-offs) makes your Flutter code cleaner, faster, and more professional.

Mastering Dart Tear-offs: Why Constructor.new is the Future of Flutter State Management

If you've been writing Flutter apps with Riverpod for a while, you've probably written something like this a hundred times — a provider that wraps a constructor in an anonymous function just to hand it back immediately. It works, but it's noise. Enter Constructor Tear-offs, a Dart 2.15+ language feature that quietly makes your state management code a lot cleaner.

The Old Way: Anonymous Functions

Here's the classic Riverpod provider definition most developers are familiar with:

// Old: wrapping constructor in an anonymous function
final stockProvider = NotifierProvider<StockNotifier, StockState>(
  () {
    return StockNotifier();
  },
);

This is perfectly valid Dart. But look closely — that anonymous function exists for one reason only: to call StockNotifier() and return it. There's no logic, no transformation, no reason for the wrapper to exist at all.

The Modern Way: Constructor Tear-offs

Dart 2.15 introduced the ability to reference a constructor directly, just like you would reference a function. Instead of writing () => StockNotifier(), you can pass StockNotifier.new — a direct reference to the constructor itself.

// New: passing constructor reference directly
final stockProvider = NotifierProvider<StockNotifier, StockState>(
  StockNotifier.new,
);

Same result. Zero wrapper. The .new is not a method call — it's a tear-off, a reference to the constructor as a callable object. Riverpod receives it and calls it when needed, exactly as before.

Side-by-Side Comparison

Here's how the two approaches look when you have multiple providers in a file:

// Before: every provider is a ceremony
final authProvider = NotifierProvider<AuthNotifier, AuthState>(
  () => AuthNotifier(),
);
final cartProvider = NotifierProvider<CartNotifier, CartState>(
  () => CartNotifier(),
);

// After: clean, consistent, scannable
final authProvider = NotifierProvider<AuthNotifier, AuthState>(AuthNotifier.new);
final cartProvider = NotifierProvider<CartNotifier, CartState>(CartNotifier.new);

The second version reads like a declaration of intent. You're not describing how to build the notifier — you're simply saying which notifier this provider uses.

Why Should You Switch?

Readability is the biggest win. Removing () { return ... } gets you straight to the point. Anyone reading your code sees immediately which Notifier is involved, without parsing a closure first.

Performance is a secondary benefit. Passing a constructor reference avoids allocating a new closure object every time the provider initializes. In most apps the difference is negligible, but it's a free improvement.

It's the standard. The official Riverpod documentation and its code generation tools now use .new as the default syntax. If you're reading modern Riverpod examples or working with generated code, you'll see this everywhere.

When to Keep the Old Syntax

There is one case where the anonymous function is still necessary: when you need to pass arguments into the constructor at initialization time. The .new tear-off only references the default, no-argument constructor — it can't carry parameters along with it.

// Still needs a closure — constructor requires an argument
final userProvider = NotifierProvider<UserNotifier, User>(
  () => UserNotifier(id: 'abc123'),
);

If your Notifier takes dependencies injected at construction time, stick with the closure. For everything else, .new is the right call.

Conclusion

Constructor tear-offs are one of those small Dart improvements that compound quietly across a codebase. Switching to StockNotifier.new won't change how your app behaves — but it will make your provider definitions cleaner, your files easier to scan, and your code aligned with where the Flutter ecosystem is heading. Sometimes the best refactor is the one that removes the most without changing anything at all.

Want to explore the full picture? Check out the flutter_riverpod package and the official Riverpod docs to see constructor tear-offs used throughout.

Share
Deephang Thegim

Deephang Thegim

Your Friendly Neighborhood