Skip to content
Skillpedia
Mobile apps280k · #36

dart-flutter-patterns

Makes your agent write code for Dart and Flutter apps. It uses modern patterns to create robust and manageable apps.

What it does

This guide provides ready-to-use code examples in Dart and Flutter. It teaches you how to structure your code following best practices for null safety, state management, navigation, and more.

When to use it

  • ✓When starting a new Flutter project.
  • ✓When needing a pattern for managing data or navigation.
  • ✓When reviewing code to ensure it follows best practices.

Example of what to ask your AI

“How can I efficiently manage my Flutter app's state using BLoC or Riverpod?”

Want more? Open the sections below.

How to use

The easiest way: copy the message below and paste it into Claude, ChatGPT, Cursor or any AI. It reads the skill and follows the instructions.

Skill link

https://github.com/affaan-m/ECC/blob/main/pi/core/skills/dart-flutter-patterns/SKILL.md

Ready-to-paste message

Use this skill to help me: https://github.com/affaan-m/ECC/blob/main/pi/core/skills/dart-flutter-patterns/SKILL.md Read the SKILL.md file at that link and follow its instructions for my task.
How it works

It provides code snippets you can copy and paste, organized by topics like null safety, immutable state, state management, and navigation.

Installation

Easiest way: copy the skill link and paste it into Claude, ChatGPT or Cursor asking it to follow the instructions.

In the terminal (Claude Code, Codex, Cursor), in your project folder:

npx skills add affaan-m/ECC --skill dart-flutter-patterns

Or download just the file:

curl -L https://raw.githubusercontent.com/affaan-m/ECC/main/pi/core/skills/dart-flutter-patterns/SKILL.md -o SKILL.md
Technical content (original SKILL.md)

Original text by the author, straight from GitHub.

Dart/Flutter Patterns

When to Use

Use this skill when:

  • Starting a new Flutter feature and need idiomatic patterns for state management, navigation, or data access
  • Reviewing or writing Dart code and need guidance on null safety, sealed types, or async composition
  • Setting up a new Flutter project and choosing between BLoC, Riverpod, or Provider
  • Implementing secure HTTP clients, WebView integration, or local storage
  • Writing tests for Flutter widgets, Cubits, or Riverpod providers
  • Wiring up GoRouter with authentication guards

How It Works

This skill provides copy-paste-ready Dart/Flutter code patterns organized by concern:

  1. Null safety — avoid !, prefer ?./??/pattern matching
  2. Immutable state — sealed classes, freezed, copyWith
  3. Async composition — concurrent Future.wait, safe BuildContext after await
  4. Widget architecture — extract to classes (not methods), const propagation, scoped rebuilds
  5. State management — BLoC/Cubit events, Riverpod notifiers and derived providers
  6. Navigation — GoRouter with reactive auth guards via refreshListenable
  7. Networking — Dio with interceptors, token refresh with one-time retry guard
  8. Error handling — global capture, ErrorWidget.builder, crashlytics wiring
  9. Testing — unit (BLoC test), widget (ProviderScope overrides), fakes over mocks

Examples

// Sealed state — prevents impossible states
sealed class AsyncState<T> {}
final class Loading<T> extends AsyncState<T> {}
final class Success<T> extends AsyncState<T> { final T data; const Success(this.data); }
final class Failure<T> extends AsyncState<T> { final Object error; const Failure(this.error); }

// GoRouter with reactive auth redirect
final router = GoRouter(
  refreshListenable: GoRouterRefreshStream(authCubit.stream),
  redirect: (context, state) {
    final authed = context.read<AuthCubit>().state is AuthAuthenticated;
    if (!authed && !state.matchedLocation.startsWith('/login')) return '/login';
    return null;
  },
  routes: [...],
);

// Riverpod derived provider with safe firstWhereOrNull
@riverpod
double cartTotal(Ref ref) {
  final cart = ref.watch(cartNotifierProvider);
  final products = ref.watch(productsProvider).valueOrNull ?? [];
  return cart.fold(0.0, (total, item) {
    final product = products.firstWhereOrNull((p) => p.id == item.productId);
    return total + (product?.price ?? 0) * item.quantity;
  });
}

Practical, production-ready patterns for Dart and Flutter applications. Library-agnostic where possible, with explicit coverage of the most common ecosystem packages.


1. Null Safety Fundamentals

Prefer Patterns Over Bang Operator

// BAD — crashes at runtime if null
final name = user!.name;

// GOOD — provide fallback
final name = user?.name ?? 'Unknown';

// GOOD — Dart 3 pattern matching (preferred for complex cases)
final display = switch (user) {
  User(:final name, :final email) => '$name <$email>',
  null => 'Guest',
};

// GOOD — guard early return
String getUserName(User? user) {
  if (user == null) return 'Unknown';
  return user.name; // promoted to non-null after check
}

Avoid late Overuse

// BAD — defers null error to runtime
late String userId;

// GOOD — nullable with explicit initialization
String? userId;

// OK — use late only when initialization is guaranteed before first access
// (e.g., in initState() before any widget interaction)
late final AnimationController _controller;

@override
void initState() {
  super.initState();
  _controller = AnimationController(vsync: this, duration: const Duration(milliseconds: 300));
}

2. Immutable State

Sealed Classes for State Hierarchies

sealed class UserState {}

final class UserInitial extends UserState {}

final class UserLoading extends UserState {}

final class UserLoaded extends UserState {
  const UserLoaded(this.user);
  final User user;
}

final class UserError extends UserState {
  const UserError(this.message);
  final String message;
}

// Exhaustive switch — compiler enforces all branches
Widget buildFrom(UserState state) => switch (state) {
  UserInitial() => const SizedBox.shrink(),
  UserLoading() => const CircularProgressIndicator(),
  UserLoaded(:final user) => UserCard(user: user),
  UserError(:final message) => ErrorText(message),
};

Freezed for Boilerplate-Free Immutability


…
FAQ

What is 'null safety'?

It's a Dart feature that helps prevent common errors that occur when a variable expected to have a value is empty (null).

What does 'immutable state' mean?

It means that once data is created, it cannot be changed directly. To modify it, you create a new version of that data, which makes the code more predictable.

Which state managers are covered?

The most popular ones: BLoC/Cubit, Riverpod, and Provider.

Details

Original description by the author

Production-ready Dart and Flutter patterns covering null safety, immutable state with Freezed, async composition, widget architecture, state management (BLoC, Riverpod, Provider), GoRouter navigation with auth guards, Dio networking, error handling, and testing. Use when writing or reviewing Dart and Flutter code — state, widgets, navigation, networking, or architecture.

repo: affaan-m/ECC

Popularity

GitHub stars
280k
Ranking position
#36
License
MIT
Updated
10/15/2026

Is this skill useful?

0

Sign in to vote.

Comments

  • …

More skills from this repository

Similar skills