π§± moarch
A Flutter CLI tool to scaffold Clean Architecture projects with Riverpod. Your conventions, your structure.
Features
- β‘ One command setup β
moarch initscaffolds your fulllib/structure with routing, theme, security, and shared widgets - π― Interactive checklist β
moarch initprompts you to select your stack (Dio/Firebase) and features (Router, CI, Tests, Media, URL launcher) - π― Layered feature generation β
moarch create feature <n>generates Clean Architecture with an interactive checklist - β¨ Minimal code generation β build_runner used only for secure
.envhandling; nofreezedorriverpod_annotationboilerplate - π§ͺ Test scaffolding β
moarch create featureauto-generates notifier/usecase tests intest/features/<feature> - ποΈ Your conventions β Fully customizable templates, pre-configured with proven patterns
- π Security included β Secure storage integration with
flutter_secure_storage - π Router ready β GoRouter setup out of the box
- π¨ Reusable widgets β Pre-built buttons, inputs, loading, action overlay, error view, and design system components
- π§ͺ CI ready β
moarch initscaffolds a GitHub Actions CI workflow with unit and integration jobs - π Flaky integration support β generated CI integration step is configured to continue on error so merges are not blocked by intermittent network/API issues
- π¦ Environment-aware β
.envand.fvmrcgenerated at project root - π± Media Service β Image picker, file picker, and video picker with permissions handling
- π URL Launcher β Launch URLs, phone numbers, and WhatsApp links
- πΆ Connectivity Service β Network connectivity monitoring with Riverpod streams
- π₯ Firebase ready β Optional Firebase Auth and Firestore providers
Installation
dart pub global activate moarch
Make sure ~/.pub-cache/bin is in your PATH:
# macOS / Linux β add to .zshrc or .bashrc
export PATH="$PATH:$HOME/.pub-cache/bin"
# Windows β add %APPDATA%\Pub\Cache\bin to your PATH via Environment Variables
Quick start
# 1. create your Flutter project
flutter create my_app && cd my_app
# 2. add dependencies to pubspec.yaml (see below)
flutter pub get
# 3. remove the generated main.dart
rm lib/main.dart
# 4. scaffold the project structure (with interactive checklist)
moarch init
# 4b. or skip checklist and generate everything
moarch init --all
# 5. create your first feature
moarch create feature auth
# 6. optional: skip test scaffolding
moarch create feature auth --no-unit --no-integration
Required dependencies
dependencies:
flutter:
sdk: flutter
flutter_riverpod:
envied:
dio:
dio_smart_retry:
go_router:
flutter_secure_storage:
logger:
mocktail:
# Optional (selected via moarch init checklist):
# firebase_core:
# firebase_auth:
# cloud_firestore:
# image_picker:
# file_picker:
# permission_handler:
# url_launcher:
# connectivity_plus:
Dev dependencies (for build_runner + envied_generator)
dev_dependencies:
lints:
test:
build_runner:
envied_generator:
Envied support (added by moarch init)
When you run moarch init, it scaffolds:
lib/config/env/app_env.dartwith@Envied(... obfuscate: true).enventries:BASE_URL=(auto-generated).gitignoreentry.env
In your app, execute codegen:
fvm flutter pub add envied
fvm flutter pub add --dev build_runner envied_generator
dart run build_runner build --delete-conflicting-outputs
Then use AppEnv values safely:
final baseUrl = AppEnv.baseUrl;
moarch init
Generates a complete, production-ready project structure and creates a GitHub Actions CI pipeline in .github/workflows/ci.yml.
.env β BASE_URL= (generated by moarch init)
.fvmrc β { "flutter": "stable" }
lib/
βββ main.dart β App with routing & theme setup
βββ core/
β βββ constants/
β β βββ app_constants.dart - spacing (4pt), text sizes, touch targets, radii, durations
β β βββ api_constants.dart - API timeout
β βββ errors/
β β βββ app_exception.dart - unified error handling
β βββ network/
β β βββ dio_client.dart - HTTP client with interceptors
β βββ security/
β β βββ secure_storage.dart - flutter_secure_storage wrapper
β βββ utils/
β βββ extensions.dart - ContextX, StringX, DateTimeX, TimeOfDayX
β βββ logger.dart - single log() function
βββ config/
β βββ env/
β β βββ app_env.dart - Envied wrapper for secure .env values
β βββ router/
β β βββ app_router.dart - GoRouter setup with routes
β βββ theme/
β βββ app_theme.dart - Material 3 theme, light/dark modes
βββ shared/widgets/
β βββ buttons/
β β βββ app_button.dart - filled / outlined / text variants
β βββ inputs/
β β βββ app_input.dart - themed input widget
β β βββ app_date_input.dart - date picker input
β β βββ app_time_input.dart - time picker input
β β βββ app_dropdown_input.dart - dropdown input widget
β βββ loadings/
β β βββ app_loading_data.dart - progress indicators for data loading
β β βββ app_loading_action_overlay.dart - indicators for actions (submit, delete)
β βββ error_view.dart - error display component
β βββ design_system_view.dart - design system showcase
βββ features/ - your features go here
.github/
βββ workflows/
βββ ci.yml - GitHub Actions CI scaffold
CHECKLIST.md - development checklist
Note on tests
moarch create featuregenerates tests intest/features/<feature>for selected layers:${feature}_notifier_test.dart${feature}_repository_test.dart(disable)${feature}_usecase_test.dart
Optional test folder for manual setup
test/
βββ features/
βββ <feature>/
βββ <feature>_notifier_test.dart
βββ <feature>_repository_test.dart (disable)
βββ <feature>_usecase_test.dart
What you get:
- β Routing configured with GoRouter
- β Secure storage integration ready
- β DIO client with error handling (or Firebase Firestore/Auth)
- β Theme system with Material 3 support
- β Reusable widgets library (buttons, inputs, loading states, error view, design system)
- β Environment variables (.env) support
- β
Enviedconfig scaffolding (lib/config/env/app_env.dart,.env+.gitignoreentry) - β
Test scaffolding in
test/features/<feature>(notifier/repository/usecase as selected) - β Extension methods for common operations (ContextX, StringX, DateTimeX, TimeOfDayX + toColor, isYesterday, timeAgo)
- β Optional: Media Service (image/file/video picker)
- β Optional: URL Launcher (URLs, phone, WhatsApp)
- β Optional: Connectivity Service (network monitoring)
moarch create feature
Generates a complete feature with Clean Architecture layers and an interactive checklist.
moarch create feature auth
moarch create feature user_profile
moarch create feature ProductCatalog # casing doesn't matter
moarch create feature auth --all # skip checklist, generate all layers
moarch create feature auth --no-unit --no-integration # skip test generation
Interactive Checklist
The CLI presents a checklist to select which layers to generate:
Select layers for "Auth" (type number, enter = confirm):
βΆ 1 [β] Remote Datasource
2 [ ] Local/Cache Datasource β optional, default: off
3 [β] Repository (interface + impl)
4 [ ] Use Cases β optional, default: off
5 [β] State + Notifier
6 [β] View
This lets you generate only what you need β skip local datasources if your feature is API-only, or skip use cases if your logic fits in the notifier.
moarch create featurealso prompts to generate tests by default. Use--no-unit --no-integrationto skip test scaffolding.
Generated Structure
lib/features/auth/
βββ domain/
β βββ entities/
β β βββ auth_entity.dart
β βββ repositories/
β β βββ auth_repository.dart β interface
β βββ usecases/
β βββ get_auth.dart β if selected
βββ data/
β βββ datasources/
β β βββ auth_remote_datasource.dart
β β βββ auth_local_datasource.dart β if selected
β βββ models/
β β βββ auth_model.dart - copyWith, fromJson, toJson
β βββ repositories/
β βββ auth_repository_impl.dart
βββ presentation/
βββ states/
β βββ auth_state.dart
βββ notifiers/
β βββ auth_notifier.dart β StateNotifier with error handling
βββ views/
β βββ auth_view.dart
Generated Test Files
moarch create feature now also generates tests in test/features/<feature>:
${feature}_notifier_test.dartβ whenState + NotifierandRepositoryare selected${feature}_repository_test.dartβ whenRepositoryis selected (disable)${feature}_usecase_test.dartβ whenUse Casesis selected
State Management Pattern
Your state uses a simple, flexible model with copyWith:
class AuthState {
const AuthState({
this.isLoadingAction = false,
this.error,
this.success,
});
final bool isLoadingAction;
final String? error;
final String? success;
AuthState copyWith({
bool? isLoadingAction,
String? error,
String? success,
}) {
return AuthState(
isLoadingAction: isLoadingAction ?? false,
error: error,
success: success,
);
}
}
Error handling in views uses state.value?.error β your AppException message from the repository, not the AsyncValue error:
ref.listen(authNotifierProvider, (_, next) {
final value = next.value;
if (value?.error != null) {
// show snackbar with value.error
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(value!.error!)),
);
}
});
Tips
- Remote datasource only? Unselect "Local/Cache Datasource" in the checklist
- No use cases? Skip them if your feature is simple β the repository covers most cases
- Reuse widgets? Put shared feature widgets in
shared/widgets/, not in the feature folder - Models with JSON? The generated model includes
fromJson()andtoJson()
Customizing moarch
moarch templates are generated from production-ready code that matches default Flutter best practices. If you want to customize what gets generated, clone the repository and modify the templates:
Template files
| File | Generates |
|---|---|
core_templates.dart |
main.dart, dio_client, secure_storage, constants, errors, utils, extensions, logger |
config_templates.dart |
app_theme.dart, app_router.dart |
shared_templates.dart |
app_button, app_input, app_loading_action, app_loading_data, error_view |
feature_templates.dart |
entity, model, datasources, repository, state, notifier, view |
test_templates.dart |
integration and notifier/use case tests |
checklist_templates.dart |
dev checklist |
ci_templates.dart |
ci workflow |
Steps to customize
-
Clone the repository
git clone https://github.com/SuperMoooo/moarch.git cd moarch -
Edit templates in
lib/src/templates/- Each method returns a string of Dart code
- Your changes will be inserted as-is into generated files
-
Re-activate locally
dart pub global activate --source path ./ -
Test your changes
moarch init moarch create feature test_feature
Pro Tips
- Keep method signatures consistent β users expect certain class names and patterns
- Use triple-quoted strings (
r'''...''') to avoid escaping special characters - Test across different feature names (snake_case, PascalCase, UPPER_CASE)
- If you change core templates, test
moarch initfirst before features - Pull requests for improvements are welcome!
Common use cases
Starting fresh
# Quick start with all layers
moarch create feature user --all
API-only feature
# Skip local datasource and use cases, generate only remote
moarch create feature products
# Then unselect "Local/Cache Datasource" and "Use Cases" in the checklist
Feature with offline support
# Select "Local/Cache Datasource" in the checklist
moarch create feature downloads
Add routing to your features
Your app_router.dart is ready for GoRouter routes. Add them under a new screen route:
GoRoute(
path: '/auth',
builder: (context, state) => const AuthView(),
),
Troubleshooting
Command not found: moarch
- Check that
~/.pub-cache/bin(or%APPDATA%\Pub\Cache\binon Windows) is in yourPATH - Try:
dart pub global activate moarchagain
Feature already exists
- moarch won't overwrite existing features β delete or rename the folder first
Wrong package imports after init
- All generated files use relative imports for core/config/shared β verify your lib structure matches
Customization not working
- After editing templates, run:
dart pub global activate --source path ./ - Make sure you've saved the file and are using the updated version
License
MIT Β© AndrΓ© Montoito