π§± moarch
A Flutter CLI tool to scaffold Clean Architecture projects with Riverpod β your conventions, your structure, no code generation required.
Features
- β‘ One command setup β
moarch initscaffolds your fulllib/structure with routing, theme, security, and shared widgets - π― 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/repository/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 button, input, loading, and error view components
- π¦ Environment-aware β
.envand.fvmrcgenerated at project root
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
moarch init
# 5. create your first feature
moarch create feature auth
Required dependencies
dependencies:
flutter:
sdk: flutter
flutter_riverpod: ^2.5.1
envied: ^1.3.3
dio: ^5.4.3
go_router: ^14.0.0
flutter_secure_storage: ^9.2.2
Dev dependencies (for build_runner + envied_generator)
dev_dependencies:
lints: ^3.0.0
test: ^1.24.0
build_runner: ^2.4.0
envied_generator: ^1.0.0
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:
.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, BASE_URL from .env
β βββ 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
β βββ 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
β βββ loadings/
β β βββ app_loading_data.dart β progress indicators for data loading
β β βββ app_loading_action.dart β indicators for actions (submit, delete)
β βββ error_view.dart β error display component
βββ features/ β your features go here
Note on tests
moarch create featuregenerates tests intest/features/<feature>for selected layers:${feature}_notifier_test.dart${feature}_repository_test.dart${feature}_usecase_test.dart
Optional test folder for manual setup
test/
βββ features/
βββ <feature>/
βββ <feature>_notifier_test.dart
βββ <feature>_repository_test.dart
βββ <feature>_usecase_test.dart
What you get:
- β Routing configured with GoRouter
- β Secure storage integration ready
- β DIO client with error handling
- β Theme system with Material 3 support
- β Reusable widgets library (buttons, inputs, loading states, error view)
- β 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
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
Interactive Checklist
The CLI presents a checklist to select which layers to generate:
Select layers for "Auth" (space = toggle, enter = confirm):
βΆ [β] Remote Datasource
[ ] Local/Cache Datasource β optional, default: off
[β] Repository (interface + impl)
[ ] Use Cases β optional, default: off
[β] State + Notifier
[β] 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.
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
βββ widgets/
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${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 |
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