A production-ready Flutter application template featuring a modular, scalable architecture with comprehensive tooling, clean architecture principles, and enterprise-grade features.
Pattern M implements a feature-based clean architecture with clear separation of concerns, making it ideal for large-scale applications that require maintainability, testability, and team collaboration.
- Clean Architecture: Strict separation between data, domain, and presentation layers
- Feature-First Structure: Modular organization by features for better scalability
- Advanced Dependency Injection: Centralized DI container with provider overrides
- Multi-Environment Support: Built-in configurations for dev, staging, and production
- Comprehensive Error Handling: Type-safe failures using Freezed with pattern matching
- Enterprise Logging: Structured logging with environment-aware configurations
- Advanced Routing: Protected routes, shell routes, and auth-aware navigation
- Type-Safe State Management: Riverpod with code generation and compile-time safety
- Rich Context Extensions: Productivity helpers for common UI operations
- Internationalization Ready: Full i18n support with ARB files and type-safe access
lib/
├── main.dart # App entry with DI and environment setup
├── app.v.dart # Root widget with global configurations
├── core/ # Core functionality and infrastructure
│ ├── config/
│ │ └── env.dart # Environment configuration and feature flags
│ ├── constants/ # App-wide constants and enums
│ ├── di/
│ │ └── injection.dart # Dependency injection container
│ ├── errors/
│ │ ├── exceptions.dart # Custom exceptions
│ │ ├── failures.dart # Freezed failure types
│ │ └── failures.freezed.dart
│ ├── extensions/ # Dart/Flutter extensions
│ │ ├── collection_extensions.dart
│ │ ├── context_extensions.dart # UI helpers (theme, navigation, dialogs)
│ │ ├── datetime_extensions.dart
│ │ ├── string_extensions.dart
│ │ └── widget_extensions.dart
│ ├── logger/
│ │ └── logger.s.dart # Structured logging service
│ ├── theme/
│ │ └── app_theme.dart # Centralized theming
│ └── utils/
│ ├── formatters.dart # Data formatting utilities
│ └── validators.dart # Input validation logic
├── features/ # Feature modules (clean architecture)
│ ├── auth/ # Authentication feature
│ │ ├── data/
│ │ │ ├── datasources/ # Remote/local data sources
│ │ │ ├── models/ # DTOs and serialization
│ │ │ └── repositories/ # Repository implementations
│ │ ├── domain/
│ │ │ ├── entities/ # Business models
│ │ │ ├── repositories/ # Repository contracts
│ │ │ └── usecases/ # Business logic
│ │ └── presentation/
│ │ ├── providers/ # State management (.p.dart)
│ │ ├── screens/ # Page widgets (.v.dart)
│ │ └── widgets/ # Feature-specific widgets
│ ├── home/ # Home feature
│ └── settings/ # Settings feature
├── l10n/ # Localization
│ ├── app_en.arb # English translations
│ ├── app_localizations.dart # Generated
│ └── app_localizations_en.dart
└── shared/ # Cross-feature shared code
├── data/
│ └── services/
│ └── storage.s.dart # Shared storage service
├── domain/
│ └── models/ # Shared domain models
└── presentation/
├── providers/ # Global providers
│ ├── auth.p.dart # Auth state provider
│ ├── router.p.dart # Router with guards
│ └── theme.p.dart # Theme state
└── widgets/ # Shared UI components
├── error_screen.dart
└── splash_screen.dart
Pattern M uses specific file suffixes for clarity and consistency:
.v.dart- Views/Screens: UI components that represent full pages.p.dart- Providers: Riverpod state management files.s.dart- Services: Business logic services (storage, API, etc.).g.dart- Generated: Auto-generated files (do not edit).freezed.dart- Freezed: Generated immutable models
- Flutter SDK ^3.8.1
- Dart SDK (included with Flutter)
- Android Studio / VS Code with Flutter extensions
-
Clone the repository
git clone <repository-url> cd pattern_m
-
Install dependencies
flutter pub get
-
Generate code
dart run build_runner build --delete-conflicting-outputs
-
Run the application
flutter run
The project heavily uses code generation for boilerplate reduction:
# One-time generation
dart run build_runner build --delete-conflicting-outputs
# Watch mode for development (recommended)
dart run build_runner watch --delete-conflicting-outputsGenerated files include:
- Riverpod providers (
*.p.g.dart) - Freezed models (
*.freezed.dart,*.g.dart) - JSON serialization (
*.g.dart) - Localization (
app_localizations*.dart)
The app supports multiple environments configured in lib/core/config/env.dart:
// Automatic environment detection
- Debug mode → Development
- Release mode → Production
- Environment variable → Staging
// Environment-specific features
- API endpoints
- Feature flags
- Timeouts
- Analytics/Crash reporting-
Create feature structure
lib/features/new_feature/ ├── data/ │ ├── datasources/ │ ├── models/ │ └── repositories/ ├── domain/ │ ├── entities/ │ ├── repositories/ │ └── usecases/ └── presentation/ ├── providers/ ├── screens/ └── widgets/ -
Implement layers bottom-up
- Start with domain entities and repositories
- Implement data layer with concrete repositories
- Create providers for state management
- Build UI screens and widgets
-
Register in DI container (if needed)
// In lib/core/di/injection.dart static Future<void> init() async { // Add your service initialization }
-
Add routes
// In lib/shared/presentation/providers/router.p.dart GoRoute( path: '/new-feature', name: 'newFeature', builder: (context, state) => const NewFeatureScreen(), ),
Provider with Code Generation
@riverpod
class FeatureName extends _$FeatureName {
@override
FeatureState build() => FeatureState.initial();
void updateState() {
state = state.copyWith(/* updates */);
}
}Async Provider
@riverpod
Future<List<Item>> fetchItems(Ref ref) async {
final repository = ref.watch(itemRepositoryProvider);
return repository.getItems();
}Pattern M uses type-safe error handling with Freezed:
// Define failures
@freezed
class Failure with _$Failure {
const factory Failure.server({
required String message,
int? statusCode,
}) = ServerFailure;
const factory Failure.network({
required String message,
}) = NetworkFailure;
}
// Handle failures
failure.when(
server: (message, code) => showServerError(message),
network: (message) => showNetworkError(message),
// ... other cases
);The framework provides rich context extensions for common operations:
// Theme access
context.primaryColor
context.textTheme.headlineLarge
// Responsive design
if (context.isMobile) // < 600px
if (context.isTablet) // 600-1200px
if (context.isDesktop) // > 1200px
// Navigation helpers
context.showErrorSnackBar('Error message');
context.showSuccessSnackBar('Success!');
context.showLoadingDialog();
context.showAppBottomSheet(child: MySheet());
// Localization
context.l10n.welcomeMessageflutter test
# With coverage
flutter test --coverage
# Generate coverage report
genhtml coverage/lcov.info -o coverage/htmltest/
├── core/
│ ├── utils/
│ └── extensions/
├── features/
│ ├── auth/
│ │ ├── domain/
│ │ ├── data/
│ │ └── presentation/
│ └── home/
└── shared/
- Test use cases with mocked repositories
- Test providers with ProviderContainer
- Use
mocktailormockitofor mocking - Focus on business logic coverage
- Never commit sensitive data (API keys, secrets)
- Use environment variables for configuration
- Implement certificate pinning for production
- Enable obfuscation for release builds
- Regular dependency updates
- Minimum SDK: 21 (Android 5.0)
- Target SDK: Latest stable
- ProGuard rules for release builds
- Minimum deployment target: 12.0
- Swift version: Latest stable
- Code signing for distribution
- Responsive design support
- PWA capabilities
- SEO optimization ready
flutter run --debugflutter run --dart-define=ENVIRONMENT=staging# Android
flutter build apk --release --obfuscate --split-debug-info=debug_info
# iOS
flutter build ios --release --obfuscate --split-debug-info=debug_info
# Web
flutter build web --release --web-renderer canvaskit-
Build runner conflicts
dart run build_runner clean dart run build_runner build --delete-conflicting-outputs
-
Pod install failures (iOS)
cd ios pod deintegrate pod install --repo-update -
Gradle issues (Android)
cd android ./gradlew clean ./gradlew build
-
Architecture
- Keep layers independent
- Depend on abstractions, not concretions
- One feature, one folder
- Shared code in
/shared
-
State Management
- Use code generation for type safety
- Keep providers focused and testable
- Dispose resources properly
-
Error Handling
- Always handle failures explicitly
- Provide user-friendly error messages
- Log errors for debugging
-
Performance
- Use const constructors
- Implement proper list optimization
- Profile before optimizing
- Monitor app size
- Follow the established architecture
- Write tests for new features
- Update documentation
- Run linting:
flutter analyze - Format code:
dart format . - Create detailed pull requests
This project is a template and can be used freely for any purpose.