what is the use of entity in flutter difference between using entity and models ?
Answer
Entity vs Model in Flutter
In Clean Architecture, Entity and Model look similar but serve completely different purposes and live in different layers of your app.
What is an Entity?
An Entity is a pure Dart class that represents your business/domain object. It has no knowledge of JSON, APIs, databases, or any external framework.
dart// domain/entities/user_entity.dart class UserEntity { final String id; final String name; final String email; final bool isActive; UserEntity({ required this.id, required this.name, required this.email, required this.isActive, }); }
Key traits:
- Pure Dart — no imports from packages
- No /text
fromJson()methodstexttoJson() - Immutable
- Contains business rules (e.g., validation logic)
What is a Model?
A Model is a data layer class that knows how to convert data from/to external sources (API JSON, database maps, SharedPreferences, etc.).
dart// data/models/user_model.dart class UserModel extends UserEntity { UserModel({ required super.id, required super.name, required super.email, required super.isActive, }); // Convert FROM JSON (API response) factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( id: json['user_id'], // API field name mapping name: json['full_name'], // Different key than entity field email: json['email_address'], isActive: json['is_active'] ?? true, ); } // Convert TO JSON (API request) Map<String, dynamic> toJson() => { 'user_id': id, 'full_name': name, 'email_address': email, 'is_active': isActive, }; }
Key traits:
- Lives in data layer
- Has /text
fromJson()methodstexttoJson() - Handles API field name mapping (e.g., →text
user_id)textid - Extends or maps to the Entity
Where to Use Entity vs Model
This is the most important part — knowing which layer calls which:
text┌─────────────────────────────────────────────────┐ │ PRESENTATION LAYER (UI) │ │ Screens, Widgets, Providers/BLoC │ │ ✅ Uses: Entity │ │ ❌ Never touches: Model │ ├─────────────────────────────────────────────────┤ │ DOMAIN LAYER (Business Logic) │ │ UseCases, Repository Interface │ │ ✅ Uses: Entity │ │ ❌ Never touches: Model │ ├─────────────────────────────────────────────────┤ │ DATA LAYER (API/Database) │ │ Repository Impl, DataSources │ │ ✅ Uses: Model (for JSON/DB conversion) │ │ ✅ Converts Model → Entity before returning │ └─────────────────────────────────────────────────┘
Where to Call Model
Only in the Data Layer — inside DataSources and Repository Implementation:
dart// data/datasources/user_remote_datasource.dart class UserRemoteDataSource { final Dio dio; UserRemoteDataSource(this.dio); Future<UserModel> getUser(String id) async { final response = await dio.get('/users/$id'); return UserModel.fromJson(response.data); // ✅ Model used here } } // data/repositories/user_repository_impl.dart class UserRepositoryImpl implements UserRepository { final UserRemoteDataSource remoteDataSource; UserRepositoryImpl(this.remoteDataSource); Future<UserEntity> getUser(String id) async { final UserModel model = await remoteDataSource.getUser(id); return model; // ✅ Model extends Entity, so it IS an Entity // The rest of the app only sees UserEntity } }
Where to Call Entity
In Domain and Presentation Layers — UseCases, Providers/BLoC, Screens:
dart// domain/usecases/get_user_usecase.dart class GetUserUseCase { final UserRepository repository; // Abstract — no Model knowledge GetUserUseCase(this.repository); Future<UserEntity> call(String id) { // ✅ Returns Entity return repository.getUser(id); } } // presentation/providers/user_provider.dart class UserNotifier extends AsyncNotifier<UserEntity> { // ✅ Entity Future<UserEntity> build() async { return ref.read(getUserUseCaseProvider).call('123'); } } // presentation/screens/user_screen.dart class UserScreen extends ConsumerWidget { Widget build(BuildContext context, WidgetRef ref) { final UserEntity user = ref.watch(userProvider).value!; // ✅ Entity return Text(user.name); // UI only knows Entity fields } }
Complete Data Flow
dart// 1. API returns JSON {"user_id": "123", "full_name": "John", "email_address": "john@email.com"} // 2. DataSource converts JSON → Model (DATA LAYER) UserModel model = UserModel.fromJson(json); // 3. Repository returns Model as Entity (BOUNDARY) UserEntity entity = model; // Model extends Entity // 4. UseCase receives Entity (DOMAIN LAYER) final user = await getUserUseCase.call('123'); // 5. UI displays Entity fields (PRESENTATION LAYER) Text(user.name); // "John"
Why Separate Them?
Imagine your API changes
full_namedisplay_namedart// ✅ Only update the Model — nothing else changes factory UserModel.fromJson(Map<String, dynamic> json) { return UserModel( name: json['display_name'], // Changed only here // ... ); } // Entity, UseCase, Provider, Screen — ZERO changes needed
Without separation, you'd update JSON parsing logic scattered across your entire app.
Comparison Table
| Aspect | Entity | Model |
|---|---|---|
| Layer | Domain (business logic) | Data (API/DB) |
| Purpose | Represent business object | Serialize/deserialize data |
| Dependencies | None (pure Dart) | JSON, DB, API packages |
| Has fromJson/toJson | No | Yes |
| Used in UI | Yes | No |
| Used in UseCases | Yes | No |
| Used in DataSources | No | Yes |
| Used in Repository | Returns Entity | Receives Model, converts to Entity |
Rule of Thumb: If you're writing
ortextfromJson()— you need a Model. If you're passing data to a UseCase, Provider, or Widget — you need an Entity. The Repository is the boundary where Model converts to Entity.texttoJson()