A powerful Flutter code generator that creates clean architecture boilerplate following industry best practices. Generate entities, models, repositories, use cases, remote data sources, dependency injection, and state management code automatically.
Unlike common Dart generators (like freezed or json_serializable) which focus on Derived Generation (creating hidden functional artifacts you never touch), this tool is a Source-to-Source Scaffolding Factory.
We believe the value of Clean Architecture is in the separation of concerns, not the typing of boilerplate. This tool handles the typing so you can focus on the logic, and it does so without taking control away from you.
- Developer Ownership: The generator produces actual human-readable Dart source files. Once generated, you own the code. You can (and should) modify, refactor, and commit these files to your repository.
- Respectful Updates: The generator is a collaborator, not a dictator. It uses a Smart Merge Engine to ensure that when you update your blueprints and regenerate, your manual customizations are preserved.
- Blueprints (
TBGfiles): Classes ending inTBG(To Be Generated) are temporary blueprints. They serve as instructions for the factory. Once your feature is scaffolded, these files are no longer needed for your app to run. You can delete them or keep them ignored in version control. - Zero Production Bloat: Since the generated code is standard Dart, both the
annotationsandgeneratorspackages are strictlydev_dependencies. Your final application binary contains zero overhead from this tool.
- Complete Clean Architecture: Generate all layers (Domain, Data, Presentation)
- Entity & Model Generation: Create domain entities and data models with JSON serialization
- Repository Pattern: Generate abstract repositories and implementations
- Use Cases: Create use cases following the single responsibility principle
- Data Sources: Generate robust remote (HTTP/API) data sources
- Interface Adapter: Generate Cubit/BLoC with comprehensive state management
- Dependency Injection: Create GetIt service locator patterns automatically
- CLI Tool: Command-line interface for easy project management
- Configuration: YAML-based configuration for customization
- Test Generation: Generate unit tests for all components
- Multi-File Output: Write generated code directly to feature files instead of .g.dart files
- Feature Scaffolding: Pre-generate feature structure from YAML configuration
- Smart 3-Way Merge: Regenerate features without losing your manual code customizations.
- Installation
- Quick Start
- CLI Usage
- Annotations Reference
- Generated Code Structure
- Best Practices
- Configuration
- Flutter SDK (>=3.0.0)
- Dart SDK (>=3.0.0)
- Git (Recommended for high-precision 3-way merging)
-
Clone the repository:
git clone https://github.com/your-username/clean_architecture_code_generator.git cd clean_architecture_code_generator -
Install dependencies for all packages:
# Install CLI dependencies cd cli && flutter pub get && cd .. # Install generator dependencies cd generators && flutter pub get && cd .. # Install annotation dependencies cd annotations && flutter pub get && cd ..
-
Install CLI globally:
cd cli dart pub global activate --source path .
Note: After activation, you can run
clean_arch_clidirectly from any project directory.
-
Initialize the tool in your target project:
clean_arch_cli init --project-name my_app cd my_app -
Add the dependencies to your
pubspec.yaml: Note: All tooling is kept indev_dependencies.dependencies: # Dependencies used by the scaffolded code equatable: ^2.0.5 dartz: ^0.10.1 get_it: ^7.6.4 dio: ^5.3.2 bloc: ^8.1.2 flutter_bloc: ^8.1.3 dev_dependencies: build_runner: ^2.4.7 # The Factory (Reference via Git or Path) annotations: git: url: https://github.com/your-username/clean_architecture_code_generator.git path: annotations generators: git: url: https://github.com/your-username/clean_architecture_code_generator.git path: generators
-
Create your first feature blueprint:
clean_arch_cli create --type feature --name authentication
-
Generate your source code:
clean_arch_cli generate
The CLI tool provides several commands to help you manage your clean architecture project:
clean_arch_cli init --project-name my_app [options]Options:
--project-name, -n: Name of the Flutter project (required)--output, -o: Output directory (default: current directory)--with-examples: Include example models and repositories (default: true)
clean_arch_cli generate [options]Options:
--path, -p: Path to Flutter project (default: current directory)--watch, -w: Watch for changes and regenerate automatically--delete-conflicting-outputs: Delete conflicting outputs before generation
The generator uses the parameter names in your TBG class as the keys for JSON serialization. If your API uses specific naming conventions (like snake_case or PascalCase), you should declare the properties in your annotated class using that exact casing.
@modelTestGen
@modelGen
@entityGen
class UserTBG {
const UserTBG({
required String id,
required String Email, // Maps to 'Email' in JSON
required String Name, // Maps to 'Name' in JSON
required Address PrimaryAddress, // Maps to 'PrimaryAddress' in JSON
required List<int> favoriteItemIds,
List<Address>? addresses,
DateTime? created_at, // Maps to 'created_at' in JSON
});
}Internal fields in the generated Entity and Model will automatically be converted to camelCase for idiomatic Dart usage, while preserving the original casing in fromMap and toMap for API compatibility.
@repoGen // Generates modifiable abstract repository
@usecaseGen // Generates modifiable use cases
@repoImplGen // Generates modifiable repository implementation
@remoteSrcGen // Generates modifiable remote data source
@injectionGen // Generates dependency injection setup
class AuthRepoTBG {
external ResultFuture<User> login({required String email, required String password});
external ResultFuture<User> register({required String email, required String password});
external ResultFuture<void> logout();
external ResultFuture<User> getCurrentUser();
}To ensure a robust and idiomatic API, the generator automatically converts Optional Positional parameters defined in your TBG blueprints into Optional Named parameters in the generated code.
Why we do this:
- Decoupling from Order: You can pass optional arguments in any order without providing
nullfor preceding ones. - Clean Architecture Consistency: It simplifies the mapping between
UseCaseparameter objects and repository methods. - Standardization: Ensures the contract across Domain, Data, and Remote layers remains consistent and easy to maintain.
Example:
// Your Blueprint (AuthRepoTBG)
external ResultFuture<void> searchUser(String query, [int? limit]);
// The Scaffolded Result (AuthRepository)
ResultFuture<void> searchUser(String query, {int? limit});When you annotate a UserRepoTBG class, the generator scaffolds actual files that follow Clean Architecture conventions. Unlike other generators, you won't find the implementation logic trapped in .g.dart files; it will be in your lib/ directory, ready for you to add your business logic.
lib/features/user/
βββ data/
β βββ datasources/
β β βββ user_remote_data_source.dart # Modifiable HTTP/API implementation
β βββ models/
β β βββ user_model.dart # Modifiable JSON serialization
β βββ repositories/
β βββ user_repository_impl.dart # Modifiable Repository implementation
βββ domain/
β βββ entities/
β β βββ user.dart # Modifiable Domain entity
β βββ repositories/
β β βββ user_repository.dart # Modifiable Abstract repository
β βββ usecases/
β βββ login.dart # Modifiable Use case
β βββ register.dart
Think of TBG files as scaffolding instructions.
- Define: Create the
TBGclass. - Scaffold: Run
generate. - Own: The generated files are standard Dart. You own them. Modify them or add business logic.
- Evolve: Need a new field? Update the
TBGand rungenerateagain. The generator will merge the new field while keeping your existing logic safe.
If you and the generator modify the exact same line, the tool will inject standard Git conflict markers:
<<<<<<< MINE (User Changes)
'email': map['Email'], // Your manual fix
=======
'email': map['email_address'], // New generator update
>>>>>>> THEIRS (Generator Output)To resolve: Simply use Android Studio or VS Code's built-in merge tools to pick the version you want. This ensures you are always the final authority on your codebase. If the IDE doesn't show merge options, you can manually edit the file to resolve the conflicts.
Technical Note: Our engine uses a hybrid approach for conflict resolution. If Git is detected in your environment, it leverages the native 3-way merge algorithm (
git merge-file) for granular, character-level precision. If not, it falls back to a strict line-based safe merge to ensure your customizations are never lost.
- Blueprints: Always end with
TBG(e.g.,UserTBG,AuthRepoTBG). - API Keys: Use mixed casing in constructor parameters if your API keys aren't camelCase.
When generating model tests, the generator creates JSON fixtures. Note that custom types (nested models) are skipped in the generated fixture file to keep it manageable. However, the generated test code automatically "hydrates" these fields in the setUpAll block by injecting CustomType.empty().toMap(), ensuring your serialization tests remain robust.
Create a clean_arch_config.yaml file in your project root to customize your factory:
# Multi-file output is highly recommended for the Scaffolding workflow
multi_file_output:
enabled: true # Recommended: Write to actual feature files
auto_create_targets: true # Auto-create missing filesHappy coding with Clean Architecture! π
For more examples and updates, visit our GitHub repository.