๐Ÿš€ raihan_cli โ€“ Flutter Feature Scaffolding CLI Tool

raihan_cli is a Dart-based command-line tool designed to automate feature creation and deletion in Flutter projects using the MVC or MVVM architectural patterns and Clean Architecture with GetX, Provider, Riverpod and BLoC state management. It helps developers maintain a clean and consistent project structure while saving time on repetitive boilerplate setup.

๐Ÿ“ฆ Installation

To install globally from the Pub.dev package:

dart pub global activate raihan_cli

Alternatively, to install from the Git repository:

dart pub global activate --source git https://github.com/raihansikdar/raihan_cli.git

๐Ÿ“ What It Does

  1. โœ… Scaffolds folders and files for new features (Clean Architecture, MVC and MVVM)

  2. ๐Ÿ› ๏ธ Supports GetX, Provider, Riverpod and BLoC state management

  3. ๐Ÿ—‘๏ธ Removes entire feature folders safely

  4. ๐Ÿ”ง Saves architecture and path preferences to reduce prompts

  5. ๐Ÿ› ๏ธ Supports custom folder paths (e.g., lib/core/feature_name) or default feature-based structure (lib/src/features/feature_name)

๐Ÿงช Basic Usage

โ–ถ๏ธ Create a New Feature

raihan_cli <feature_name>

Example: raihan_cli product

Youโ€™ll be prompted to choose:

1๏ธโƒฃ Folder Structure Type:

1: Default (lib/src/features/<feature_name>)

2: Custom (lib/<custom_path>/<feature_name>)

Note: You must configure the path type on the first run. The package will remember your choice.

2๏ธโƒฃ State Management:

  1. getx

  2. provider

  3. riverpod

  4. bloc

  5. others

Note: You must configure the state management on the first run. The package will remember your choice.

3๏ธโƒฃ Architecture type:

  1. mvc

  2. mvvm

  3. clean architecture

Note: You must configure Architecture on the first run. The tool will remember your choice.

Then your feature folder will create successfully.

If folder is not showing then collapse your parent folder like this

raihan_cli

๐Ÿ—‘๏ธ Remove an Existing Feature

raihan_cli remove <feature_name>

Example: raihan_cli remove product
Note: If folder is still showing then collapse your parent folder.

This confirms and deletes the feature directory based on your saved configuration..

๐Ÿ†• Advanced Commands

โ–ถ๏ธ Create Nested Sub Feature

raihan_cli subfolder <parent/sub_feature>
raihan_cli subfolder <parent/sub_feature> [state] [architecture]

Example: raihan_cli subfolder auth/login
Example: raihan_cli subfolder auth/login riverpod mvvm

  • Creates nested feature like auth/login
  • Uses your selected architecture + state management
  • Does not overwrite saved config

๐Ÿงฉ Create Feature-To-Feature API Module (ftof)

raihan_cli ftof <feature/api>
raihan_cli ftof <feature/api> [state] [architecture]

Example: raihan_cli ftof home/category
Example: raihan_cli ftof home/category riverpod mvvm

  • Creates API module folders without views
  • Supports mvc, mvvm, clean
  • Supports getx, provider, riverpod, bloc, others

๐Ÿ—‘๏ธ Remove Nested Sub Feature

raihan_cli remove subfolder <parent/sub_feature>

Example: raihan_cli remove subfolder auth/login

๐Ÿ—‚๏ธ Remove Only Inside Elements (Keep Parent Folder)

raihan_cli remove elements <feature_name>

Example: raihan_cli remove elements auth

  • Deletes all contents inside auth
  • Keeps auth folder

๐Ÿงน Remove ftof API Module Folders

raihan_cli remove ftof <feature/api>

Example: raihan_cli remove ftof home/category

  • Deletes:
    • model/<api>
    • repository/<api>
    • state folder <api> (based on selected state system)

๐Ÿงพ Remove ftof Parent Files

raihan_cli remove ftof-parent <feature>

Example: raihan_cli remove ftof-parent home

  • Removes common parent files such as:
    • <feature>_model.dart
    • <feature>_repository.dart
    • <feature>_repository_impl.dart
    • <feature>_notifier.dart / <feature>_provider.dart

๐Ÿ”„ Reset Configuration (if did mistake)

# Windows
del tool\.cli_architecture_config

# macOS/Linux
rm tool/.cli_architecture_config

โœ… Deactivating the CLI Package:

dart pub global deactivate raihan_cli

๐Ÿ’ก Architecture + State Management Examples

๐Ÿ“ MVC Folder Structure

๐Ÿ“ MVC + GetX

lib/src/features/<feature_name>/    # if custom path is "features"
โ”œโ”€โ”€ controllers/
โ”‚   โ””โ”€โ”€ <feature_name>_controller.dart
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ MVC + Provider

lib/src/features/<feature_name>/      # if custom path is "features"
โ”œโ”€โ”€ provider/
โ”‚   โ””โ”€โ”€ <feature_name>_provider.dart
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ MVC + Riverpod

lib/src/features/<feature_name>/      
โ”œโ”€โ”€ riverpod/
โ”‚   โ”œโ”€โ”€ <feature_name>_notifier.dart      # StateNotifier / AsyncNotifier class
โ”‚   โ””โ”€โ”€ <feature_name>_provider.dart      # Riverpod provider exposing the notifier
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/
    

๐Ÿ“ MVC + BLoC

lib/src/features/<feature_name>/       # if custom path is "features"
โ”œโ”€โ”€ bloc/
โ”‚   โ”œโ”€โ”€ <feature_name>_bloc.dart
โ”‚   โ”œโ”€โ”€ <feature_name>_event.dart
โ”‚   โ””โ”€โ”€ <feature_name>_state.dart
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ MVVM Folder Structure

๐Ÿ“ MVVM + GetX

lib/features/<feature_name>/     # if custom path is "features"
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ”œโ”€โ”€ view_model/
โ”‚   โ””โ”€โ”€ <feature_name>_view_model.dart
โ”œโ”€โ”€ repository/
โ”‚   โ”œโ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ MVVM + Provider

lib/features/<feature_name>/       # if custom path is "features"
โ”œโ”€โ”€ provider/ 
โ”‚   โ””โ”€โ”€ <feature_name>_provider.dart
โ”œโ”€โ”€ repository/
โ”‚   โ”œโ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ MVVM + Riverpod

lib/features/<feature_name>/           
โ”œโ”€โ”€ riverpod/
โ”‚   โ”œโ”€โ”€ <feature_name>_notifier.dart      # StateNotifier / AsyncNotifier class
โ”‚   โ””โ”€โ”€ <feature_name>_provider.dart      # Riverpod provider exposing the notifier
โ”œโ”€โ”€ repository/
โ”‚   โ”œโ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ MVVM + BLoC

lib/features/<feature_name>/      # if custom path is "features"
โ”œโ”€โ”€ bloc/
โ”‚   โ”œโ”€โ”€ <feature_name>_bloc.dart
โ”‚   โ”œโ”€โ”€ <feature_name>_event.dart
โ”‚   โ””โ”€โ”€ <feature_name>_state.dart
โ”œโ”€โ”€ repository/
โ”‚   โ”œโ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ model/
โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ””โ”€โ”€ views/
    โ”œโ”€โ”€ screen/
    โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
    โ””โ”€โ”€ widgets/

๐Ÿ“ Clean Architecture Folder Structure

๐Ÿ“ Clean Architecture + GetX

lib/features/<feature_name>/        # if custom path is "features"/
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ data_source/
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_remote_data_source.dart
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_remote_data_source_impl.dart
โ”‚   โ”œโ”€โ”€ model/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ”‚   โ””โ”€โ”€ repository/
โ”‚       โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ entities/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_entities.dart
โ”‚   โ”œโ”€โ”€ repository/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ use_case/
โ”‚       โ””โ”€โ”€ <feature_name>_use_case.dart
โ”œโ”€โ”€ presentation/
โ”‚   โ”œโ”€โ”€ controller/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_controller.dart
โ”‚   โ””โ”€โ”€ views/
โ”‚       โ”œโ”€โ”€ screen/
โ”‚       โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
โ”‚       โ””โ”€โ”€ widgets
โ””โ”€โ”€ <feature_name>_dependency_injection.dart

๐Ÿ“ Clean Architecture + Provider

lib/features/<feature_name>/        # if custom path is "features"/
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ data_source/
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_remote_data_source.dart
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_remote_data_source_impl.dart
โ”‚   โ”œโ”€โ”€ model/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ”‚   โ””โ”€โ”€ repository/
โ”‚       โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ entities/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_entities.dart
โ”‚   โ”œโ”€โ”€ repository/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ use_case/
โ”‚       โ””โ”€โ”€ <feature_name>_use_case.dart
โ”œโ”€โ”€ presentation/
โ”‚   โ”œโ”€โ”€ provider/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_provider.dart
โ”‚   โ””โ”€โ”€ views/
โ”‚       โ”œโ”€โ”€ screen/
โ”‚       โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
โ”‚       โ””โ”€โ”€ widgets
โ””โ”€โ”€ <feature_name>_dependency_injection.dart

๐Ÿ“ Clean Architecture + Riverpod

lib/features/<feature_name>/        # if custom path is "features"/
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ data_source/
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_remote_data_source.dart
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_remote_data_source_impl.dart
โ”‚   โ”œโ”€โ”€ model/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ”‚   โ””โ”€โ”€ repository/
โ”‚       โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ entities/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_entities.dart
โ”‚   โ”œโ”€โ”€ repository/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ use_case/
โ”‚       โ””โ”€โ”€ <feature_name>_use_case.dart
โ”œโ”€โ”€ presentation/
โ”‚   โ”œโ”€โ”€ riverpod/
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_notifier.dart 
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_provider.dart 
โ”‚   โ””โ”€โ”€ views/
โ”‚       โ”œโ”€โ”€ screen/
โ”‚       โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
โ”‚       โ””โ”€โ”€ widgets
โ””โ”€โ”€ <feature_name>_dependency_injection.dart

๐Ÿ“ Clean Architecture + BLoC

lib/features/<feature_name>/        # if custom path is "features"/
โ”œโ”€โ”€ data/
โ”‚   โ”œโ”€โ”€ data_source/
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_remote_data_source.dart
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_remote_data_source_impl.dart
โ”‚   โ”œโ”€โ”€ model/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_model.dart
โ”‚   โ””โ”€โ”€ repository/
โ”‚       โ””โ”€โ”€ <feature_name>_repository_impl.dart
โ”œโ”€โ”€ domain/
โ”‚   โ”œโ”€โ”€ entities/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_entities.dart
โ”‚   โ”œโ”€โ”€ repository/
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_repository.dart
โ”‚   โ””โ”€โ”€ use_case/
โ”‚       โ””โ”€โ”€ <feature_name>_use_case.dart
โ”œโ”€โ”€ presentation/
โ”‚   โ”œโ”€โ”€ bloc/
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_bloc.dart
โ”‚   โ”‚   โ”œโ”€โ”€ <feature_name>_event.dart
โ”‚   โ”‚   โ””โ”€โ”€ <feature_name>_state.dart
โ”‚   โ””โ”€โ”€ views/
โ”‚       โ”œโ”€โ”€ screen/
โ”‚       โ”‚   โ””โ”€โ”€ <feature_name>_screen.dart
โ”‚       โ””โ”€โ”€ widgets
โ””โ”€โ”€ <feature_name>_dependency_injection.dart

๐Ÿ‘จโ€๐Ÿ’ป Author

Raihan Sikdar

Website: raihansikdar.com
Email: raihansikdar10@gmail.com
GitHub: raihansikdar
LinkedIn: raihansikdar

๐Ÿ“œ License

This package is licensed under the MIT License.

Libraries

raihan_cli