Clean Architecture Use Cases: The Conductors of Your App
In our previous article, we explored Entities—the pure business rules at the center of the onion. But entities are just data and logic; they don’t do anything on their own. Today, we move to the next layer: Clean Architecture Use Cases.

What are Use Cases?
If Entities are the “noun” of your app (e.g., a User), the Use Case is the “verb” (e.g., GetUserProfile, UpdateEmail, or ProcessPayment).
A Use Case contains Application-Specific Business Rules. It orchestrates the flow of data to and from the entities, and directs those entities to use their enterprise-wide business rules to achieve the goals of the use case.
The Orchestration Rule
The beauty of Clean Architecture Use Cases is that they act as a bridge. They take input from the UI (via a Controller or Presenter), talk to a Repository to get data, perform logic using an Entity, and then send the result back out.
Crucially, the Use Case doesn’t care where the data comes from (SQL, Firebase, or a Mock) or how it’s displayed (Flutter, Web, or Console). It only cares about the operation’s logic.
Key Takeaway: If you change the UI, the Use Cases don’t change. If you change the Database, the Use Cases don’t change. They only change if the actual process of the business changes.
Practical Code Example
Let’s see how a Use Case looks in a Flutter/Dart project. Imagine we want to fetch a user profile.
// Domain Layer: use_cases/get_user_profile.dart
import '../entities/user_entity.dart';
import '../repositories/user_repository.dart';
class GetUserProfile {
final UserRepository repository;
// We inject the repository interface, not the implementation!
GetUserProfile(this.repository);
Future<UserEntity> execute(String userId) async {
// 1. Fetch data from repository
final user = await repository.fetchUser(userId);
// 2. Perform any application-specific logic
if (user.name.isEmpty) {
throw Exception("User profile is incomplete");
}
// 3. Return the entity
return user;
}
}
Why is this better?
- Testability: You can easily test
GetUserProfileby passing a “Mock” version of theUserRepository. No internet connection required! - Readability: Anyone looking at your folder structure can see a list of “Use Cases” and immediately understand exactly what your app does.
- Independence: The logic of “fetching a profile” is now protected from the messy details of API calls and JSON parsing.
Conclusion
Clean Architecture Use Cases are the brain of your application. They keep your UI simple and your data layer flexible. By separating “what the app does” from “how the app looks,” you create a system that is built to last.
In the next part, we will discuss the Interface Adapters—specifically the Repository Pattern—and how they bridge the gap between our pure logic and the outside world.
Link to the Single Responsibility Principle page, as Use Cases are the ultimate example of this.
One response to “Clean Architecture Use Cases: Part 03 (The Logic Controller)”
[…] our previous article, we learned about Use Cases—the conductors of our application. But here is the big question: […]