Classic clean architecture vs the Flutter guide: a terminology map
In the Flutter world the phrase "clean architecture" means two different things, and that is the main source of confusion.
1. The community template. Three folders per feature: domain (entities, repository interfaces, a separate UseCase class per operation), data (models/DTOs, data sources, repository implementations), presentation (bloc/notifier, page, widgets). Errors are returned as Either<Failure, T>, DI is wired with get_it + injectable. The template is inspired by Robert C. Martin's four circles but is not the same thing.
2. Robert C. Martin's original principles. The four circles and the dependency rule. No folder names, no packages, no UseCase class template.
The Flutter team's official guide is a third, lighter variant: two layers (UI + data), MVVM, an optional domain layer.
All three are worth knowing, because a conversation rarely states which one it means.
| Classic term | In the Flutter guide | Typical file |
|---|---|---|
| Entity | Domain model | `domain/models/product.dart` |
| Use case / interactor | Use case — an optional layer | `domain/usecases/place_order.dart` |
| Repository (interface) | Abstract repository | `domain/repositories/order_repository.dart` |
| Repository implementation | Repository (in the data layer) | `data/repositories/order_repository_remote.dart` |
| Remote / local data source | Service | `data/services/order_api_client.dart` |
| Model / DTO | API model (keeping it separate is a conditional recommendation) | `data/dto/order_dto.dart` |
| Presentation (bloc/cubit) | View model | `ui/orders/order_list_notifier.dart` |
| `Either<Failure, T>` | `Result<T>` (an official design pattern) | `utils/result.dart` |
| `get_it` + `injectable` | DI — `provider` in the guide, Riverpod here | `main.dart` / provider files |
| Question | Community template | Official Flutter guide |
|---|---|---|
| Use case classes | A separate class per operation — mandatory | Optional; only when one of three conditions holds |
| Separate DTO and domain model | Always (model plus entity) | Conditional — recommended in large apps |
| How errors are returned | `Either<Failure, T>` (fpdart or dartz) | `Result<T>` — a sealed class, with Dart's own `switch` |
| Folder layout | Feature-first: three layers inside each feature | Hybrid: UI by feature, data by layer |
| Amount of boilerplate | 10-15 files for one CRUD feature | 4-6 files for the same feature |
| When it pays off | Large team, long lifetime, serious domain logic | In practically any project |
The strongest answer to "do you use clean architecture?" is to list the rules, not the template's name: what the layers are, which way dependencies point, what each layer lets you test. Then you can add: "we don't always write use cases, because the official guide treats them as conditional — ours exist only where two repositories are combined".
That answer shows two things: you understand the principles, and you are not copying a template unthinkingly.
Practice. Fill in the terminology table above for your own project (or for a "flutter clean architecture" sample you find on GitHub): which class matches which classic term. Done means: at least six rows are filled and one or two terms carry a "we don't have this, because …" note.
📚 Sources and documentation
- The Clean Architecture (Robert C. Martin)blog.cleancoder.com
The original source — no `UseCase` class template, no `Either`, no folder names in it. Worth reading precisely to see the gap between the template and the principles.
- Guide to app architectureofficialdocs.flutter.dev
Two layers plus an optional domain layer: the official position.
- Architecture recommendationsofficialdocs.flutter.dev
The list of "conditional" items — it shows which parts of the template are not mandatory.