flutter_arch_cli 0.4.0
flutter_arch_cli: ^0.4.0 copied to clipboard
A CLI tool to scaffold Flutter projects with your chosen architecture, state management, and production-ready extras.
flutter_arch_cli #
A CLI tool to scaffold Flutter projects with your chosen architecture, state management, and the production-ready extras every real app needs.
Skip the day-one setup decisions. Pick how you want to build, and flutter_arch writes the boilerplate for you — folder structure, state management plumbing, networking client, storage services, theming, lint rules, an assets/ folder ready to drop files into, and a working main.dart that launches on first try.
Table of contents #
- Why this exists
- Features at a glance
- Install
- Quick start
- What you get in detail
- Generated project structure
- Example walkthrough
- FAQ
- Roadmap
- Contributing
- Author
- License
Why this exists #
Every Flutter project starts with the same set of decisions. Which architecture? Which state management? How do I wire up dio properly? Where does the theme live? How do I configure analysis_options.yaml so it's strict but not annoying? Should I use shared_preferences, hive, or flutter_secure_storage? Probably all three, depending on what I'm storing.
You can spend the first half-day of every new project answering these questions. Or you can answer them once, encode the answers as a CLI, and never repeat yourself.
flutter_arch_cli is that CLI. It asks you the high-level questions in under a minute, then writes thousands of lines of correct, lint-clean, immediately-runnable boilerplate so you can skip straight to building features.
Features at a glance #
- Two architectures — Clean Architecture (layered) or Feature-first (flat)
- Three state management options — Riverpod, Bloc, or Provider
- Optional Riverpod code generation —
riverpod_generator+freezed, withbuild_runnerrun for you - Networking —
DioClientwith logger and auth interceptors - Five storage options — pick any combination of
shared_preferences,hive,isar,sqflite,flutter_secure_storage - Material 3 theming — light and dark themes derived from a single seed color
- Assets folder — pre-organised subfolders for images, icons, fonts, animations, and translations, with pubspec registration handled for you
- Lint setup —
very_good_analysiswith sensible overrides - Tests folder — mirrors your
lib/structure - A working
main.dart—flutter runlaunches a real, interactive app the moment generation finishes - AI agent context — optional
CLAUDE.md,AGENTS.md, and.cursorrulesfiles so Claude Code, Cursor, Windsurf, Copilot and every other AI agent picks up your project's conventions automatically
Install #
dart pub global activate flutter_arch_cli
Make sure ~/.pub-cache/bin is on your PATH. If it isn't, add this to your shell config (~/.zshrc, ~/.bashrc, or equivalent):
export PATH="$PATH:$HOME/.pub-cache/bin"
Then reload your shell:
source ~/.zshrc
Verify the install:
flutter_arch --help
You should see the help text with the create command listed.
Quick start #
flutter_arch create my_app
Walk through the prompts:
Let's set up your Flutter project.
? Organization (e.g. com.yourcompany) (com.example) › com.yourname.myapp
? Pick an architecture › Clean Architecture
? Pick a state management solution › Riverpod
? Use code generation (riverpod_generator + freezed)? Recommended for new projects. (Y/n) › yes
? Pick the extras you want set up (space to toggle, enter to confirm) ›
◉ Networking (dio + interceptors)
◉ Local storage (shared_preferences + hive)
◉ Theming (light/dark, Material 3)
◉ Linting (very_good_analysis)
◉ Tests folder structure
? Pick the storage solution(s) you want › shared_preferences, flutter_secure_storage
Then run it:
cd my_app
flutter run
You'll see a sample screen with a refresh button. Tap it — three list items appear after a brief loading spinner. That's loading, success, and error state handling wired correctly out of the box.
What you get in detail #
Architecture #
Clean Architecture organises each feature into three layers:
data/— datasources, models, repository implementationsdomain/— entities, repository interfaces, usecasespresentation/— pages, widgets, state management
Plus a shared core/ directory for cross-cutting concerns. This pattern scales well to large teams and long-lived codebases because it enforces clear boundaries between business logic and framework code.
Feature-first is flatter. Each feature is a self-contained directory with models/, repository/, pages/, widgets/, and a state folder. No three-layer split, no abstract repositories. The right choice for smaller apps or solo projects where the ceremony of Clean Architecture is overkill.
Both options scaffold a working sample feature so you can see the pattern in action and use it as a reference when adding your own.
State management #
You get a real, working sample provider/bloc for whichever option you pick, plus the right wrapper applied in main.dart (ProviderScope, MultiBlocProvider, or MultiProvider).
Each sample demonstrates the same three states — loading, success, error — so you learn the canonical pattern for that library regardless of which one you chose.
Code generation for Riverpod #
If you pick Riverpod, you'll be asked whether to enable code generation. If you say yes:
riverpod_generator,freezed,build_runnerare added to yourpubspec.yaml- Your sample state class is generated as a
@freezedimmutable class - Your sample provider is written using the
@riverpodannotation - The CLI runs
dart run build_runner build --delete-conflicting-outputsautomatically afterflutter pub get
If build_runner fails for any reason (most commonly a network issue while resolving generators), the CLI prints the exact command for you to run manually so you're never stuck.
If you say no to codegen, you get the classic StateNotifierProvider pattern with a hand-written state class — perfect for learning the underlying mental model before moving to generation.
Networking #
A DioClient class is generated at lib/core/network/dio_client.dart with:
BaseOptionsconfigured with sensible timeouts and JSON headers- A typed wrapper around
get,post,put,delete - A
LoggerInterceptorthat prints requests and responses in debug builds only - An
AuthInterceptorwith atokensetter ready to wire into your storage solution, plus a hook for handling 401 responses (token refresh, sign-out, etc.)
Drop it into your DI of choice and you have a production-shaped HTTP layer from line one.
Storage #
You can pick any combination of:
shared_preferences— simple key-value, great for user settings and feature flagshive— fast NoSQL, great for cached domain modelsisar— modern type-safe NoSQL with built-in queryingsqflite— classic SQL, great when you need joins or migrationsflutter_secure_storage— encrypted, the right home for auth tokens and secrets
Each one you pick gets a dedicated service file under lib/core/storage/ that wraps the package with an app-friendly API. Common combinations like shared_preferences + flutter_secure_storage are first-class — your app initializes each service in main.dart automatically.
Theming #
Material 3 light and dark themes are generated at lib/core/theme/app_theme.dart, derived from a single seed color in lib/core/theme/app_colors.dart. Change the seed, the whole app retones.
main.dart wires both themes into MaterialApp with themeMode: ThemeMode.system, so your app respects the user's OS preference by default.
Assets #
Every project is scaffolded with an assets/ folder containing:
images/— for PNG, JPG, WebPicons/— for SVG and small UI iconsfonts/— for custom typographyanimations/— for Lottie and Rive filestranslations/— for localization JSON
Each subfolder has a README explaining how to use it. Placeholder files are included where appropriate (a 1×1 transparent PNG, a blank SVG, a minimal Lottie JSON, a sample English translation) so flutter run works on first try without "asset not found" errors.
A typed AppAssets class is generated at lib/core/constants/app_assets.dart so you can reference assets via constants:
Image.asset(AppAssets.placeholderImage)
Instead of stringly-typed paths that break silently when you rename a file.
The relevant subfolders are pre-registered in pubspec.yaml. Fonts are not auto-registered because they need their own fonts: block — the README in assets/fonts/ shows you the exact syntax when you add your first font.
Linting #
very_good_analysis is included with overrides for the rules that tend to nag more than help in app code:
lines_longer_than_80_chars— disabledflutter_style_todos— disabledprefer_const_constructors— disabled (your formatter handles this)avoid_redundant_argument_values— disabledsort_pub_dependencies— disabledalways_use_package_imports— disabled (relative imports inside features are idiomatic)public_member_api_docs— disabled (you're writing an app, not a library)
The result: strict where it matters, quiet where it'd just create noise.
Tests #
A test/ folder is scaffolded that mirrors your lib/ structure, with a placeholder test in your sample feature. Replace it with real tests as you go — the directory shape is already set up so you never have to think about where a new test file belongs.
AI agent context #
If you tick the "AI agent context" extra, the CLI generates three files at your project root that adapt to your specific choices:
CLAUDE.md— read by Claude CodeAGENTS.md— the emerging AI-agnostic standard, read by Cursor, Windsurf, and others.cursorrules— Cursor's older format, still widely used
The content is generated to match the architecture and state management you picked — a Bloc project gets Bloc conventions, a Riverpod-with-codegen project gets the @riverpod + freezed patterns spelled out. The agent then has correct guidance from the moment it opens the project, including:
- Folder conventions and where new code belongs
- How to add a new feature, model, repository, or screen
- Hard rules about not bypassing the architecture, not hardcoding assets, not introducing alternative state management
- Codegen commands if applicable
These files are designed to travel with the repo, so every contributor on the project benefits regardless of which AI tool they use.
Generated project structure #
Here's what a maximally-configured project looks like (Clean Architecture + Riverpod with codegen + all extras + shared_preferences and flutter_secure_storage storage):
my_app/
├── assets/
│ ├── animations/
│ │ ├── README.md
│ │ └── placeholder.json
│ ├── fonts/
│ │ └── README.md
│ ├── icons/
│ │ ├── README.md
│ │ └── placeholder.svg
│ ├── images/
│ │ ├── README.md
│ │ └── placeholder.png
│ └── translations/
│ ├── README.md
│ └── en.json
├── lib/
│ ├── core/
│ │ ├── constants/
│ │ │ └── app_assets.dart
│ │ ├── errors/
│ │ │ ├── exceptions.dart
│ │ │ └── failures.dart
│ │ ├── network/
│ │ │ ├── dio_client.dart
│ │ │ └── interceptors/
│ │ │ ├── auth_interceptor.dart
│ │ │ └── logger_interceptor.dart
│ │ ├── storage/
│ │ │ ├── preferences_service.dart
│ │ │ └── secure_storage_service.dart
│ │ └── theme/
│ │ ├── app_colors.dart
│ │ └── app_theme.dart
│ ├── features/
│ │ └── sample/
│ │ ├── data/
│ │ │ ├── datasources/
│ │ │ ├── models/
│ │ │ │ └── sample_model.dart
│ │ │ └── repositories/
│ │ ├── domain/
│ │ │ ├── entities/
│ │ │ │ └── sample_entity.dart
│ │ │ ├── repositories/
│ │ │ │ └── sample_repository.dart
│ │ │ └── usecases/
│ │ └── presentation/
│ │ ├── pages/
│ │ │ └── sample_page.dart
│ │ ├── providers/
│ │ │ ├── sample_provider.dart
│ │ │ ├── sample_provider.g.dart
│ │ │ ├── sample_state.dart
│ │ │ └── sample_state.freezed.dart
│ │ └── widgets/
│ └── main.dart
├── test/
│ ├── core/
│ └── features/
│ └── sample/
│ └── domain/
│ └── sample_test.dart
├── analysis_options.yaml
└── pubspec.yaml
Example walkthrough #
Let's say you're starting a new project for a small e-commerce app. You want Clean Architecture (it's going to grow), Bloc (your team is comfortable with it), dio for HTTP, flutter_secure_storage for the auth token, and shared_preferences for things like onboarding flags.
flutter_arch create shop_app
Walk through:
? Organization (e.g. com.yourcompany) (com.example) › com.yourname.shop
? Pick an architecture › Clean Architecture
? Pick a state management solution › Bloc
? Pick the extras you want set up (space to toggle, enter to confirm) ›
◉ Networking (dio + interceptors)
◉ Local storage (shared_preferences + hive)
◉ Theming (light/dark, Material 3)
◉ Linting (very_good_analysis)
◉ Tests folder structure
? Pick the storage solution(s) you want ›
◉ shared_preferences (simple key-value)
◯ hive (NoSQL, fast)
◯ isar (modern type-safe DB)
◯ sqflite (classic SQL)
◉ flutter_secure_storage (encrypted, for tokens/secrets)
The CLI then:
- Runs
flutter createto scaffold the base project - Cleans out the default
main.dartand widget test - Scaffolds the Clean Architecture layout
- Generates the Bloc sample feature (
SampleBloc,SampleEvent,SampleState) - Generates
DioClient,LoggerInterceptor,AuthInterceptor - Generates
PreferencesServiceandSecureStorageService - Generates
AppTheme,AppColors - Generates the assets folder with placeholders
- Writes
analysis_options.yamlwithvery_good_analysis - Scaffolds the test folder
- Writes
main.dartwithMultiBlocProvider,MaterialApp, theme wiring, storage init, and the sample page - Updates
pubspec.yamlwith all dependencies and asset paths - Runs
flutter pub get
Now:
cd shop_app
flutter run
You're looking at a working app. Time to delete the sample feature and start building your real ones — but the entire scaffolding is done.
FAQ #
Does flutter_arch_cli work on Windows?
Yes. The CLI is pure Dart and uses cross-platform path handling. Make sure flutter is on your PATH.
Does it modify existing projects?
No. flutter_arch create only creates new projects. It refuses to run if a folder with the target name already exists. A separate flutter_arch generate feature <name> command for adding features to existing projects is on the roadmap.
Can I change my mind after generation?
Yes. The output is just code. Swap state management, change folder structure, delete the storage service you didn't end up needing — it's your project from the moment generation finishes.
Why is routing not in the extras?
Routing is the most opinionated layer of any app and the conventions shift faster than the rest. Forcing go_router (or any specific choice) felt like it'd age poorly. It's high on the roadmap as an optional extra.
Why doesn't the generated analysis_options.yaml use the most aggressive very_good_analysis rules?
Because new projects shouldn't open with 20 lint warnings on day one. The overrides drop the rules that are bikeshed-y in app code and keep the ones that catch real issues. You can re-enable any of them in your own analysis_options.yaml whenever you're ready.
Will you add my favourite state management option / architecture / package?
Open an issue and let's discuss. The bar is "would a meaningful share of the Flutter community pick this over what's already supported." If yes, it's a candidate.
Roadmap #
- Routing (
go_router) scaffold as an optional extra - Custom feature generator:
flutter_arch generate feature <name> - Optional Firebase setup (Core, Auth, Firestore, Crashlytics)
- Template export so teams can fork their own house style
bloc_testandmocktailsetup when Bloc is chosenjson_serializableas an opt-in alongsidefreezed- VS Code snippet pack matching the generated patterns
Contributing #
PRs are welcome. The repository lives at github.com/JesutoniAderibigbe/flutter_arch_cli.
If you find a bug:
- Open an issue with the command you ran, the choices you made, and the unexpected behaviour
- If you have a fix, send a PR referencing the issue
If you want to add a feature:
- Open an issue first to discuss the design — saves rework
- Follow the existing patterns: abstract generator interface + concrete implementations
- Update the README, CHANGELOG, and example walkthrough
Author #
Built by Jesutoni Aderibigbe — a Flutter engineer based in Ibadan, Nigeria, who got tired of writing the same boilerplate at the start of every project.
- GitHub: @JesutoniAderibigbe
- LinkedIn: jesutoni-aderibigbe
- Medium: @aderibigbejesutoni860
- dev.to: @toniaderibigbe
License #
MIT — see LICENSE for details.