Version 2.1.0 - View Changelog
A production-ready Flutter template for building small to medium-sized applications, refined through years of real-world client projects.
Working in outsource companies and developing apps for various clients, I needed a reliable, flexible template that could be quickly adapted to different project requirements. After developing each app, I continuously updated and refined this template, incorporating best practices and lessons learned from production deployments.
Special Thanks: This template builds upon the excellent foundation created by my former colleague Andrey Kaschenko. His original architecture and engineering approach continue to inspire and influence significant portions of this template.
In client projects, it's common to have multiple apps sharing the same backend or design system (e.g., customer app + admin app). By separating the UIKit and Toolkit into independent packages:
- Toolkit (shared utilities package): Share business logic, API clients, and utilities across apps
- UIKit (Flutter widgets): Reuse UI components while allowing customization per app
This modular approach has proven invaluable when building app families for clients, dramatically reducing development time and improving code consistency.
This template provides a complete, production-ready foundation with:
- Clean three-layer architecture (Presentation → Domain → Data)
- BLoC state management with Freezed
- Repository pattern with abstract DataSources
- Dependency injection with GetIt (modular configuration)
- Repository executors with decorator pattern (retry, caching, error handling)
- Two-layer exception handling (domain exceptions + UI models)
- Authentication flow (login, registration, token management)
- User profile management
- Settings (theme toggle, language selection)
- Task management with calendar (example feature)
- Theme system (light/dark mode)
- Localization (English & Russian)
- Environment configuration (mock, dev, prod)
- 145 tests passing (100% pass rate)
- Comprehensive BLoC and integration tests
- Full-stack integration testing for all features
- Zero analyzer warnings
- Custom lint rules (starter_lints package)
- Extensive documentation (CLAUDE.md + /docs)
- Type-safe API client with response-based methods
- Code generation for routes, models, exceptions
- UIKit example app showcasing all components
- Theme-aware widgets with consistent styling
- Complete localization setup
- AI-friendly documentation (optimized for Codex and Claude Code)
fvm flutter pub get
fvm flutter analyze
fvm flutter test --concurrency 4
fvm flutter run- Update API base URLs in
lib/core/consts/core_consts.dart - Update store URLs in
lib/core/consts/core_consts.dart - Confirm environment defaults (
mock,dev,prod) inlib/features/application/environment/model/app_environment.dart - Set your app version in
pubspec.yamland keepCoreConsts.appVersionin sync - Run code generation if you changed models/routes/localization:
fvm flutter pub run build_runner build --delete-conflicting-outputsfvm flutter --no-color pub global run intl_utils:generate
GitHub Actions is configured in .github/workflows/ci.yml and runs:
flutter pub getdart run custom_lint --no-fatal-infos --no-fatal-warningsflutter analyzeflutter test --concurrency 4locally, with CI also split across per-feature shards in parallel
Optional strict lint gate:
- Use Run workflow (
workflow_dispatch) withstrict_lint = trueto rundart run custom_lint --no-fatal-infos(fatal warnings, infos reported).
flutter_starter/
├── lib/
│ ├── core/ # App-wide configuration
│ │ ├── consts/ # Constants (API URLs, etc.)
│ │ ├── di/ # Dependency injection modules
│ │ ├── router/ # Navigation (auto_route)
│ │ └── data/ # Core data layer
│ │
│ ├── features/ # Feature modules
│ │ ├── auth/ # Authentication (login, registration)
│ │ ├── profile/ # User profile
│ │ ├── settings/ # App settings (theme, language)
│ │ ├── task/ # Example feature (task management)
│ │ └── application/ # Global app state
│ │
│ ├── l10n/ # Localization files
│ └── main.dart # App entry point
│
├── packages/
│ ├── starter_toolkit/ # Shared utilities and data infrastructure
│ │ ├── data/ # API client, exceptions, executors
│ │ ├── utils/ # Helpers, validators, formatters
│ │ └── README.md
│ │
│ ├── starter_uikit/ # Flutter UI components
│ │ ├── widgets/ # Reusable widgets
│ │ ├── theme/ # Theme system
│ │ ├── example/ # Demo app
│ │ └── README.md
│ │
│ └── starter_lints/ # Custom lint rules
│ ├── lib/src/lints/ # Lint implementations
│ └── README.md
│
├── test/ # Tests (145 tests, 100% pass rate)
├── docs/ # Documentation
├── CLAUDE.md # AI assistant guide (14.5KB)
└── README.md # This file
Each feature follows a consistent pattern:
features/feature_name/
├── data/ # DataSource implementations
│ ├── remote_x_data_source.dart
│ └── local_x_data_source.dart
│
├── domain/ # Repository + abstract DataSource
│ ├── x_repository.dart
│ └── x_data_source.dart
│
├── model/ # Data models
│ └── x_model.dart
│
├── configs/ # DI module
│ └── x_module.dart
│
└── ui/ # Presentation layer
├── bloc/ # BLoC (state management)
├── screen/ # UI screens
└── widget/ # UI widgets
Type-safe HTTP client with response-based methods:
// Clear intent - returns User object
final user = await client.requestJson<User>(
method: HttpMethod.get,
path: '/users/123',
fromJson: User.fromJson,
);
// Clear intent - returns void
await client.requestVoid(
method: HttpMethod.delete,
path: '/users/123',
);Two-layer architecture with sealed classes:
// In BLoC - store domain exception
try {
final data = await _repository.getData();
return emit(State.success(data));
} on AppException catch (e) {
return emit(State.failure(e));
}
// In UI - map to localized model
final uiModel = ExceptionUiMapper(context).map(exception);
FailureWidgetLarge(exception: exception, onRetry: _retry);Decorator pattern for cross-cutting concerns:
final executor = RawRepositoryExecutor()
.withErrorHandling() // Convert exceptions
.withRetry() // Exponential backoff
.withCaching(); // Time-based cache
Future<List<User>> getUsers() {
return _executor.execute(() => _dataSource.getUsers());
}Centralized theme management:
final theme = ThemeProvider.of(context).theme;
final textStyles = ThemeProvider.of(context).textStyles;
Container(color: theme.primary)
Text('Hello', style: textStyles.mediumBody14)Multi-package localization support:
// Main app
Localizer.of(context).login
// Toolkit (error messages)
ToolkitLocalizer.of(context).errorMessageNoConnection
// UIKit (widget labels)
UikitLocalizer.of(context).retryThe template includes comprehensive tests:
# Run all tests
fvm flutter test --concurrency 4
# Run with coverage
fvm flutter test --coverage --concurrency 4
# View coverage report
genhtml coverage/lcov.info -o coverage/html
open coverage/html/index.htmlTest Summary:
- 145 tests passing (100% pass rate)
- Unit Tests: 111 tests (BLoC, repositories, data sources)
- Integration Tests: 34 tests (full-stack flows)
Integration Test Coverage:
- ✅ Auth (LoginBloc, RegistrationBloc)
- ✅ Task (CalendarBloc, TasksListBloc, TaskDeleteBloc)
- ✅ Profile (UserBloc)
- ✅ Settings (LanguageCubit, ThemeCubit)
- ✅ Application (EnvironmentCubit)
The template uses several code generators:
# Routes, JSON, Freezed models
fvm flutter pub run build_runner build --delete-conflicting-outputs
# Exception mappers (custom tool)
dart run utils/generators/generate_exception_mapper.dart
# Localization files
fvm flutter --no-color pub global run intl_utils:generate
# Asset references
fvm flutter pub run spider build
# App icons
fvm flutter pub run flutter_launcher_icons
# Splash screen
fvm flutter pub run flutter_native_splash:createWhat it provides:
- API client with type-safe methods
- Exception system with sealed classes
- Repository executors (retry, caching, error handling)
- Date/time helpers and extensions
- Form validators and formatters
- BLoC utilities
Use it for: Shared business logic across multiple apps
What it provides:
- Status widgets (loading, empty, error states)
- App bars (title, base, transparent)
- Buttons (elevated, outlined with loading)
- Form components (text fields, dropdowns, date pickers)
- Notifications (snackbar)
- Theme system (light/dark mode)
- Exception UI mapper
- Interactive example app
Use it for: Consistent UI across apps sharing design
What it provides:
avoid_widget_functions- Prohibit_build*functions returning Widgetprefer_arrow_except_build- Arrow for callbacks, block forbuild()onlyalways_spread_in_collections- Require spread operator in collectionsbloc_no_bloc_dependency- BLoCs cannot inject other BLoCsblank_line_before_return- Require blank line before returnsort_constructor_params- Order: required → defaults → optional → super
Use it for: Enforcing consistent code style across the project
The template includes extensive documentation:
- AGENTS.md - Comprehensive guide for Codex and agentic coding assistants
- CLAUDE.md - Companion guide for Claude Code workflows
- AI Context - Concise AI-friendly cheat-sheets per topic
- Architecture Guide - Three-layer architecture, dependency inversion
- BLoC & Freezed Guide - State management patterns
- Code Review Guide - Severity-based review checklist
- Estimation Guide - Story-point estimation method
- Exception Handling - Two-layer exception system, code generation
- Structure Guide - File organization, feature layout
- Testing Guide - Testing strategies, patterns, best practices
- Coding Rules - Consolidated rule set + lint mapping
- BLoC File Rules - File layout & basic flow
- Code Formatting - Code style, BLoC patterns, conventions
- Git Workflow - Branch / commit / PR naming
- Naming Conventions - Consistent naming patterns
- Create feature directory:
lib/features/my_feature/ - Follow the feature structure pattern (data, domain, model, ui, configs)
- Create DI module extending
AppModule - Register module in
app_configurator.dart - Add routes to
app_router.dart - Write tests in
test/features/my_feature/
Edit theme files in packages/starter_uikit/lib/theme/:
app_theme.dart- Colors, dimensionsapp_text_styles.dart- Typography- Update example app to preview changes
- Add language code to
pubspec.yaml→flutter_intl: - Create
lib/l10n/intl_[lang].arb - Run:
fvm flutter --no-color pub global run intl_utils:generate - Repeat for toolkit and uikit packages
-
Create exception class with
@ExceptionUiConfig:@ExceptionUiConfig( titleKey: 'errorTitle', descriptionKey: 'errorDescription', snackbarKey: 'errorSnackbar', ) final class MyException extends AppException { const MyException(); // ... }
-
Run generator:
dart run utils/generators/generate_exception_mapper.dart
-
Add localization keys to ARB files
- Update
pubspec.yamlin all packages:main_locale: [code] - Create main ARB file:
lib/l10n/intl_[code].arb - Regenerate:
fvm flutter --no-color pub global run intl_utils:generate
Core:
- Flutter 3.32.0 (managed via FVM)
- Dart 3.0.0+
State Management:
- flutter_bloc 9.1.1
- freezed 2.5.8
Navigation:
- auto_route 9.2.2
Dependency Injection:
- get_it 8.2.0
Networking:
- dio 5.9.0
Storage:
- flutter_secure_storage 9.2.4
Forms:
- flutter_form_builder 10.1.0
Localization:
- intl 0.20.2
- intl_utils 2.8.8
Testing:
- bloc_test
- mocktail
- http_mock_adapter
Private template for internal use. Feel free to fork and adapt for your projects.
- Original Architecture: Andrey Kaschenko - The foundation and engineering principles
- Template Evolution: Refined through multiple client projects
- Inspiration: Real-world production requirements and challenges