- β No State Management
- β No Dependency Injection
- β Only core architecture (Domain + Data + Presentation)
π§ What is Clean Architecture?
Clean Architecture is a design approach where an application is divided into layers to achieve:
- Well-organized code
- Easier maintenance and updates
- Better testability
- Scalability for large applications
π The Golden Rule
- Dependencies always point inward
- Inner layers are independent and do not know about outer layers
Presentation β Domain β Data
π§± The 3 Core Layers
1. Domain Layer (Core Logic)
- The brain of the application
- Contains business rules
- Written in pure Dart (no Flutter, no APIs)
2. Data Layer (Implementation)
- Handles API calls or local database
- Implements contracts defined in the Domain layer
3. Presentation Layer (UI)
- Displays UI
- Handles user interactions
π Recommended Folder Structure
lib/
βββ features/
β βββ user/
β βββ domain/
β βββ data/
β βββ presentation/
π Step-by-Step Implementation (API Example)
Letβs walk through a simple example:
π Fetch User from API
π§ Step 1: Domain Layer (Start Here)
π lib/features/user/domain/
β 1.1 Entity (First File)
π entities/user.dart
class User {
final int id;
final String name;
User({required this.id, required this.name});
}
β Represents core data
β Has no dependency on external layers
β 1.2 Repository (Abstract)
π repositories/user_repository.dart
abstract class UserRepository {
Future<User> getUser();
}
β Defines what data is needed
β Does not include implementation
β 1.3 Use Case
π usecases/get_user.dart
class GetUser {
final UserRepository repository;
GetUser(this.repository);
Future<User> call() {
return repository.getUser();
}
}
β Represents a business action
β This is what the UI will call
πΎ Step 2: Data Layer
π lib/features/user/data/
β 2.1 Model
π models/user_model.dart
import '../../domain/entities/user.dart';
class UserModel extends User {
UserModel({required int id, required String name})
: super(id: id, name: name);
factory UserModel.fromJson(Map<String, dynamic> json) {
return UserModel(
id: json['id'],
name: json['name'],
);
}
}
β Maps API response to your app structure
β 2.2 Data Source (API Call)
π datasources/user_remote_data_source.dart
class UserRemoteDataSource {
Future<UserModel> getUser() async {
// Fake API call
await Future.delayed(Duration(seconds: 1));
return UserModel(id: 1, name: "Ali");
}
}
β Contains actual API logic
β 2.3 Repository Implementation
π repositories/user_repository_impl.dart
class UserRepositoryImpl implements UserRepository {
final UserRemoteDataSource remoteDataSource;
UserRepositoryImpl(this.remoteDataSource);
@override
Future<User> getUser() async {
return await remoteDataSource.getUser();
}
}
β Implements the Domain contract
π¨ Step 3: Presentation Layer (Simple UI)
π lib/features/user/presentation/
β Simple UI Page (Without State Management)
π pages/user_page.dart
class UserPage extends StatefulWidget {
@override
_UserPageState createState() => _UserPageState();
}
class _UserPageState extends State<UserPage> {
String text = "Press Button";
void fetchUser() async {
final dataSource = UserRemoteDataSource();
final repository = UserRepositoryImpl(dataSource);
final usecase = GetUser(repository);
final user = await usecase();
setState(() {
text = user.name;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: ElevatedButton(
onPressed: fetchUser,
child: Text(text),
),
),
);
}
}
β Direct and simple connection
β Easy for beginners (no Bloc, no Provider)
π Data Flow Explained
UI β UseCase β Repository β DataSource β API
API β DataSource β Repository β UseCase β UI
β‘ Recommended Development Order
- Entity
- Repository (abstract)
- Use Case
- Model
- Data Source
- Repository Implementation
- UI
β Common Mistakes to Avoid
- Calling APIs directly from UI β
- Mixing Models and Entities β
- Importing Flutter into Domain layer β
π― Final Summary
- Domain β Defines business logic
- Data β Implements logic
- Presentation β Displays results
π βAlways start with the Domain β never with the UI.β
π Whatβs Next?
- State Management (Bloc, Riverpod)
- Dependency Injection (e.g., get_it)
Clean Architecture is the foundation everything else builds on.
π Explore More Blogs
If you found this guide helpful, explore more mobile app development articles on our blog.