โก Thunder CLI
Create Flutter apps with GetX, BLoC or Cubit in seconds, then generate features, API models, Postman collection code and translations from the command line.
โจ What it does
| Command | What you get |
|---|---|
thunder init |
A new Flutter app (GetX, BLoC or Cubit) with networking, services, middleware, DI, routing, localization, theme and sample features |
thunder feature <name> |
View + controller / bloc / cubit + repository + API endpoint + DI + route |
thunder model |
A model class (fromJson / toJson) from an API response or a JSON file |
thunder c_api |
API constants, body/response models, repositories and controllers / blocs / cubits from a Postman collection |
thunder localization |
Your texts translated to any language and wired into the app |
Everything Thunder generates compiles and passes flutter analyze on the current Flutter stable,
for all three state managements (checked on every change by tool/e2e.sh).
| GetX | BLoC | Cubit | |
|---|---|---|---|
| State | GetxController |
Bloc + events + state |
Cubit + state |
| DI | Get.lazyPut (bindings_app.dart) |
get_it (injection.dart) |
get_it (injection.dart) |
| Routing | GetPage |
go_router |
go_router |
| Middleware | GetMiddleware |
go_router redirect guard |
go_router redirect guard |
| Template | getx branch |
bloc branch |
cubit branch |
๐ Installation
dart pub global activate thunder_cli
Make sure the pub cache bin folder is in your PATH
(how).
You also need Flutter installed for thunder init.
thunder version
๐ Quick start
GetX
thunder init shop_app --org com.company --state getx
cd shop_app
thunder feature product_details # controller + view + repo, Get.toNamed(Routes.PRODUCT_DETAILS)
flutter run
BLoC
thunder init shop_app --org com.company --state bloc
cd shop_app
thunder feature product_details # bloc + event + state + view + repo, context.push(Routes.PRODUCT_DETAILS)
flutter run
Cubit
thunder init shop_app --org com.company --state cubit
cd shop_app
thunder feature product_details # cubit + state + view + repo, context.push(Routes.PRODUCT_DETAILS)
flutter run
Leave out --state and Thunder asks (GetX is the default). The choice is saved in thunder.json,
so every later command generates code for the right style.
๐ง๐ปโ๐ป Commands
Run any command without options and Thunder asks for what it needs.
Pass the options to skip the questions, and add -y (--yes) to never be asked anything (CI, scripts).
thunder init [name]
Runs flutter create (platform folders and application id), then puts the template for your state management on
top of it: lib/, test/, assets/, pubspec.yaml and analysis_options.yaml, renamed to your app.
The templates live in Thunder-Template (one branch per style);
when there is no internet Thunder uses the copy bundled with it.
thunder init shop_app --org com.company --state bloc
thunder init shop_app --org com.company --state getx --title "Shop" --platforms android,ios --remote https://github.com/me/shop_app.git
thunder init shop_app --template https://github.com/me/my_template#main # your own template
| Option | Description |
|---|---|
--state, -s |
getx, bloc or cubit (asked when missing, default getx) |
--org |
Organization in reverse domain notation (com.company โ app id com.company.shop_app) |
--title |
App title (default: from the name, Shop App) |
--path |
Folder to create the project in (default: the name) |
--platforms |
Platforms for flutter create (default: all) |
--template |
Your own template: GitHub URL (add #branch), git URL, .zip URL or a local folder |
--offline |
Use the template bundled with Thunder (no download) |
--[no-]git |
Create a git repository with a first commit (default: on) |
--remote |
Push the first commit to this GitHub repository |
--[no-]github-action |
Add a workflow that builds the APK and sends it to Telegram |
--[no-]vscode |
Open the project in VS Code |
What you get (BLoC shown; GetX uses bindings/ and app_routes.dart, Cubit uses cubit/ folders):
lib/
โโโ main.dart MaterialApp.router + SettingsBloc (theme & language)
โโโ core/
โ โโโ di/injection.dart get_it: sl<HomeRepo>()
โ โโโ config/app_config.dart app name + environment (--dart-define=ENV=prod)
โ โโโ middlewares/auth_guard.dart route guard
โ โโโ networking/ DioHelper (token interceptor) โ ApiResult, ApiCallStatus, RequestType
โ โโโ routing/ routes.dart + app_router.dart
โ โโโ services/ StorageService, ThemeService, LocalizationService
โ โโโ theme/app_theme.dart Material 3 light & dark themes
โโโ helper/
โ โโโ constants/ api_constants.dart (BASE_URL), strings_constants.dart
โ โโโ translations/ en + ar, local.dart
โ โโโ widgets/ CustomText, CustomButton, ApiStateWidget
โโโ app/
โโโ features/home/ home_view.dart + bloc/ (a list loaded from an API)
โโโ features/settings/ dark mode + language switch, saved locally
โโโ repositories/home_repo.dart
โโโ models/todo_model.dart
thunder feature <name>
thunder feature product_details
GetX:
โ
Create lib/app/features/product_details/product_details_controller.dart
โ
Create lib/app/features/product_details/product_details_view.dart
โ
Create lib/app/repositories/product_details_repo.dart
โ
Register 'product_details' in bindings_app.dart
โ
Add '/product_details' to routes.dart and app_routes.dart
BLoC:
โ
Create lib/app/features/product_details/bloc/product_details_bloc.dart
โ
Create lib/app/features/product_details/bloc/product_details_event.dart
โ
Create lib/app/features/product_details/bloc/product_details_state.dart
โ
Create lib/app/features/product_details/product_details_view.dart
โ
Create lib/app/repositories/product_details_repo.dart
โ
Register 'product_details' in injection.dart
โ
Add '/product_details' to routes.dart and app_router.dart
Cubit:
โ
Create lib/app/features/product_details/cubit/product_details_cubit.dart
โ
Create lib/app/features/product_details/cubit/product_details_state.dart
โ
Create lib/app/features/product_details/product_details_view.dart
โ
Create lib/app/repositories/product_details_repo.dart
โ
Register 'product_details' in injection.dart
โ
Add '/product_details' to routes.dart and app_router.dart
The new page loads ApiConstants.productDetails when it opens and shows loading / error / empty / data states.
Open it with Get.toNamed(Routes.PRODUCT_DETAILS) (GetX) or context.push(Routes.PRODUCT_DETAILS) (BLoC / Cubit).
Existing files are kept; use --force to overwrite.
Thunder finds the style in thunder.json. In a project without it (for example one made with Use this template),
it looks at the files: lib/core/di/injection.dart means BLoC (or Cubit when there are cubit/ folders), otherwise GetX.
thunder model
# from an API
thunder model --name post --url https://jsonplaceholder.typicode.com/posts
thunder model --name login --url https://dummyjson.com/auth/login --method post \
--body '{"username": "emilys", "password": "emilyspass"}'
# from a JSON file
thunder model --name user --json user.json
Creates lib/app/models/post_model.dart:
class PostModel {
int? userId;
int? id;
String? title;
String? body;
PostModel({this.userId, this.id, this.title, this.body});
factory PostModel.fromJson(Map<String, dynamic> json) {
return PostModel(
userId: (json['userId'] as num?)?.toInt(),
id: (json['id'] as num?)?.toInt(),
title: json['title']?.toString(),
body: json['body']?.toString(),
);
}
Map<String, dynamic> toJson() { ... }
}
Nested objects become their own classes, lists of objects become List<XModel> (keys of every element are merged),
numbers are read safely and keys like class, first-name or 2fa are renamed to valid Dart names.
thunder c_api
Export your collection from Postman (Export โ Collection v2.1), then:
thunder c_api --collection my_api.postman_collection.json
โ
Read 2 variables and 8 requests (BLoC project)
โ
Add 8 routes to api_constants.dart
โ
Build 4 models
โ
Build 3 repositories and blocs: auth, products, general
POST auth/login โ AuthBloc โ LoginRequested
GET products/{id} โ ProductsBloc โ GetProductRequested
- One repository per top-level folder (requests outside folders go to
general), plus a controller (GetX), a bloc with one event per request (BLoC) or a cubit with one method per request (Cubit). - Typed responses are kept in the bloc / cubit state (
state.loginResponse). - The base URL variable (
{{base_url}}) becomesApiConstants.baseUrl. - Path variables (
:id,{{id}}) become method parameters. - JSON bodies become body models; saved example responses become typed response models.
- form-data bodies are sent as
FormData.
Try it with example/demo.postman_collection.json.
thunder localization
Write your texts in lib/helper/constants/strings_constants.dart:
class StringsConstants {
static const String home = "Home";
static const String login = "Log in";
}
Then:
thunder localization --from en --to ar,fr
Thunder writes ar_translation.dart, fr_translation.dart, registers them in local.dart and adds them to
LocalizationService.supportedLocales. Use the texts with Text(StringsConstants.home.tr) in every style.
Switch language with LocalizationService.changeLocale('ar') (GetX) or the settings bloc / cubit
(SettingsLanguageChanged('ar') / changeLanguage('ar')); the template's settings page already does it.
Run the command again after adding texts: only the new ones are translated. Translations come from Google Translate,
so review them before you ship.
๐ Upgrading from 2.x
The old flags still work (thunder --init, --feature, --model, --c_api, --localization, --help).
Projects made with 2.x are GetX projects, and Thunder treats them that way.
In a project created with 2.x, Thunder adds new routes and bindings after your existing ones when it cannot find
its // thunder: markers. The generated code expects the 3.0 networking files (lib/core/networking/:
DioHelper.safeApiCall, ApiResult, ApiCallStatus, RequestType), so compare yours with a fresh
thunder init project first.
๐งช Development
dart pub get
dart test # unit tests
./tool/e2e.sh # for getx, bloc and cubit: creates an app, runs every command,
# then flutter analyze + flutter test
# after changing the Thunder-Template branches, refresh the offline copy:
dart run tool/bundle_templates.dart <getx-dir> <bloc-dir> <cubit-dir>
๐ค Contributing
Issues and pull requests are welcome. Please run dart format ., dart analyze and dart test before opening a PR.
๐จ Contact
WhatsApp ยท Telegram ยท GitHub
๐ License
MIT โ see LICENSE.
Libraries
- thunder_cli
- Thunder CLI: create Flutter projects with GetX, BLoC or Cubit and generate features, models, API code and translations.