Artisan-inspired CLI for Flutter, powered by the Magic Framework.
Scaffold controllers, models, views, migrations, and more — with a single command.
Website · pub.dev · Issues · Discussions
Alpha Release — Magic CLI is under active development. APIs may change before stable. Star the repo to follow progress.
Flutter projects require a lot of boilerplate — models, controllers, migrations, views, policies, seeders, factories, providers. Creating each file manually means remembering directory conventions, import paths, and class structures every time.
Magic CLI fixes this. One command generates the correct file in the correct directory with the correct structure:
# Before — manual boilerplate
# Create file, remember the path, copy-paste template, fix imports, add to config...
# After — Magic way
magic make:model User -mcfsp
# ✓ Created: lib/app/models/user.dart
# ✓ Created: lib/database/migrations/m_20260324_120000_create_users_table.dart
# ✓ Created: lib/app/controllers/user_controller.dart
# ✓ Created: lib/database/factories/user_factory.dart
# ✓ Created: lib/database/seeders/user_seeder.dart
# ✓ Created: lib/app/policies/user_policy.dartIf you know Laravel's Artisan, you already know Magic CLI.
| Feature | Description | |
|---|---|---|
| 🏗️ | 16 Generators | make:model, make:controller, make:view, make:migration, make:policy, and 11 more |
| ⚡ | Composite Scaffolding | make:model -mcfsp generates model + migration + controller + factory + seeder + policy in one command |
| 📁 | Nested Paths | make:controller Admin/Dashboard → lib/app/controllers/admin/dashboard_controller.dart |
| 🔧 | Project Initialization | magic install sets up the full Magic directory structure and config files |
| 🔑 | Key Generation | magic key:generate creates secure encryption keys in .env |
| 🎨 | Smart Suffixes | make:controller User and make:controller UserController both work — no double-suffix bugs |
| 📝 | Stub Templates | Customizable .stub files with {{ placeholder }} syntax |
dart pub global activate magic_cliEnsure ~/.pub-cache/bin is in your PATH.
cd my_flutter_app
magic installmagic make:model Post -mcf
magic make:view Dashboard --stateful
magic make:middleware Auth
magic make:enum Status| Command | Description |
|---|---|
magic install |
Initialize Magic in a Flutter project |
magic key:generate |
Generate a new application encryption key |
| Command | Description |
|---|---|
magic make:model Name |
Create an Eloquent model class |
magic make:controller Name |
Create a controller class |
magic make:view Name |
Create a view class |
magic make:migration name |
Create a database migration |
magic make:policy Name |
Create an authorization policy |
magic make:seeder Name |
Create a database seeder |
magic make:factory Name |
Create a model factory |
magic make:provider Name |
Create a service provider |
magic make:middleware Name |
Create a middleware class |
magic make:enum Name |
Create a string-backed enum |
magic make:event Name |
Create an event class |
magic make:listener Name |
Create an event listener |
magic make:request Name |
Create a form request with validation |
magic make:lang code |
Create a language JSON file |
Initializes the Magic Framework in your Flutter project — creates directories, config files, providers, routes, and bootstraps main.dart.
magic install
magic install --without-database --without-authOptions:
| Option | Description |
|---|---|
--without-database |
Skip database setup |
--without-auth |
Skip authentication setup |
--without-network |
Skip network setup |
--without-cache |
Skip cache setup |
--without-events |
Skip events setup |
--without-localization |
Skip localization setup |
--without-logging |
Skip logging setup |
--without-broadcasting |
Skip broadcasting setup |
Generated Structure
lib/
├── config/
│ ├── app.dart
│ ├── auth.dart
│ ├── broadcasting.dart
│ ├── cache.dart
│ ├── database.dart
│ ├── logging.dart
│ ├── network.dart
│ └── view.dart
├── app/
│ ├── controllers/
│ ├── models/
│ ├── policies/
│ ├── middleware/
│ └── providers/
│ ├── app_service_provider.dart
│ └── route_service_provider.dart
├── database/
│ ├── migrations/
│ ├── seeders/
│ └── factories/
├── resources/
│ └── views/
├── routes/
│ └── app.dart
├── main.dart
├── .env
└── .env.example
Creates an Eloquent-style model with optional related files.
magic make:model User
magic make:model Post -mcf # model + migration + controller + factory
magic make:model Comment -mcfsp # all related files
magic make:model Comment --all # same as -mcfsp
magic make:model Admin/Profile # nested pathOptions:
| Option | Short | Description |
|---|---|---|
--migration |
-m |
Create a migration file |
--controller |
-c |
Create a controller |
--factory |
-f |
Create a model factory |
--seeder |
-s |
Create a seeder |
--policy |
-p |
Create a policy |
--all |
-a |
Create all related files |
--force |
-F |
Overwrite existing files |
Creates a controller class. Suffix Controller is auto-appended.
magic make:controller User # → lib/app/controllers/user_controller.dart
magic make:controller UserController # Same result — smart suffix handling
magic make:controller Admin/Dashboard # → lib/app/controllers/admin/dashboard_controller.dart
magic make:controller Post --resource # Resource controller with CRUD methods
magic make:controller Post --resource --model Post # Resource with model bindingOptions:
| Option | Short | Description |
|---|---|---|
--resource |
-r |
Generate CRUD methods (index, show, store, update, destroy) |
--model |
-m |
Specify the model for resource controller |
Creates a view class. Suffix View is auto-appended.
magic make:view Login # → lib/resources/views/login_view.dart
magic make:view Auth/Register # → lib/resources/views/auth/register_view.dart
magic make:view Dashboard --stateful # Stateful view with lifecycle hooksOptions:
| Option | Description |
|---|---|
--stateful |
Generate a stateful view with lifecycle hooks |
Creates a timestamped migration file.
magic make:migration create_users_table
magic make:migration create_posts_table --create=posts
magic make:migration add_email_to_users --table=usersOptions:
| Option | Short | Description |
|---|---|---|
--create |
-c |
The table to be created (uses create stub) |
--table |
-t |
The table to migrate |
Output: lib/database/migrations/m_YYYYMMDDHHMMSS_create_users_table.dart
Creates an authorization policy. Suffix Policy is auto-appended.
magic make:policy Post # → lib/app/policies/post_policy.dart
magic make:policy Post --model=Post # With model binding
magic make:policy Admin/Dashboard # Nested pathOptions:
| Option | Short | Description |
|---|---|---|
--model |
-m |
The model the policy applies to |
All generators support --force to overwrite existing files and nested paths via / separator.
# Service provider — auto-appends ServiceProvider suffix
magic make:provider App # → lib/app/providers/app_service_provider.dart
# Seeder — auto-appends Seeder suffix
magic make:seeder User # → lib/database/seeders/user_seeder.dart
# Factory — auto-appends Factory suffix
magic make:factory User # → lib/database/factories/user_factory.dart
# Form request — auto-appends Request suffix
magic make:request StoreUser # → lib/app/requests/store_user_request.dart
# Middleware
magic make:middleware Auth # → lib/app/middleware/auth_middleware.dart
# Enum with value/label and selectOptions
magic make:enum Status # → lib/app/enums/status.dart
# Event class
magic make:event UserRegistered # → lib/app/events/user_registered_event.dart
# Event listener
magic make:listener SendWelcomeEmail # → lib/app/listeners/send_welcome_email_listener.dart
# Language file
magic make:lang tr # → assets/lang/tr.jsonGenerates a secure encryption key and writes it to .env.
magic key:generateUpdates your .env file with:
APP_KEY=base64:randomGeneratedKey...
Magic CLI exports its infrastructure for other plugins to build on — custom commands, stub loaders, file helpers, and console styling.
# pubspec.yaml in your plugin
dependencies:
magic_cli: ^0.0.1import 'package:magic_cli/magic_cli.dart';
class MakeJobCommand extends GeneratorCommand {
@override
String get name => 'make:job';
@override
String get description => 'Create a new job class';
@override
String getDefaultNamespace() => 'lib/app/jobs';
@override
String getStub() => 'job';
@override
Map<String, String> getReplacements(String name) {
final parsed = StringHelper.parseName(name);
return {
'{{ snakeName }}': StringHelper.toSnakeCase(parsed.className),
};
}
}ConsoleStyle — ANSI-colored output, tables, formatted messages
// Output methods (available via Command base class)
success('Created successfully'); // ✓ green
error('File not found'); // ✗ red
info('Processing...'); // ℹ blue
warn('File already exists'); // ⚠ yellow
// Interactive prompts
final name = ask('Project name?', defaultValue: 'my_app');
final ok = confirm('Continue?', defaultValue: true);
// Tables
table(['Name', 'Status'], [
['User', 'Active'],
['Admin', 'Inactive'],
]);FileHelper — File I/O, YAML, project root detection
FileHelper.fileExists('pubspec.yaml');
FileHelper.readFile('lib/main.dart');
FileHelper.writeFile('lib/config/app.dart', content);
FileHelper.ensureDirectoryExists('lib/app/models');
FileHelper.findProjectRoot();
final yaml = FileHelper.readYamlFile('pubspec.yaml');StubLoader — Template loading and placeholder replacement
// Load and replace in one step
final content = await StubLoader.make('controller', {
'className': 'UserController',
'namespace': 'lib/app/controllers',
});
// Or separately
final stub = await StubLoader.load('model');
final result = StubLoader.replace(stub, {
'className': 'Post',
'tableName': 'posts',
});ConfigEditor — pubspec.yaml and Dart file editing
ConfigEditor.addDependencyToPubspec(
pubspecPath: 'pubspec.yaml',
name: 'my_package',
version: '^1.0.0',
);
ConfigEditor.addImportToFile(
filePath: 'lib/config/app.dart',
importStatement: "import 'package:my_app/app/providers/custom_provider.dart';",
);StringHelper — Case conversion and name parsing
StringHelper.toPascalCase('user_profile'); // UserProfile
StringHelper.toSnakeCase('UserProfile'); // user_profile
StringHelper.toCamelCase('user_profile'); // userProfile
StringHelper.toPlural('post'); // posts
// Nested path parsing
final parsed = StringHelper.parseName('Admin/Dashboard');
// parsed.directory → 'admin'
// parsed.className → 'Dashboard'
// parsed.fileName → 'dashboard'Magic CLI uses a Kernel-based command registry — inspired by Laravel Artisan:
bin/magic.dart (entry point)
↓
Kernel.register(commands)
↓
Kernel.handle(args) → lookup by name → parse flags → command.handle()
↓
GeneratorCommand: load .stub → replace {{ placeholders }} → write file
Command types:
- GeneratorCommand — base for all
make:*commands (stub loading + placeholder replacement) - Command — base for utility commands (
install,key:generate)
Stub system: .stub files in assets/stubs/ with {{ className }}, {{ namespace }}, and custom placeholders. StubLoader resolves stubs via multi-strategy path resolution.
git clone https://github.com/fluttersdk/magic_cli.git
cd magic_cli && flutter pub get
flutter test && dart analyzeReport a bug · Request a feature
MIT — see LICENSE for details.
Built with care by FlutterSDK
If Magic CLI saves you time, give it a star — it helps others discover it.