Android Clean Architecture
Clean Architecture patterns for Android and KMP projects. Covers module boundaries, dependency inversion, UseCase/Repository patterns, and data layer design with Room, SQLDelight, and Ktor.
When to Activate
- Structuring Android or KMP project modules
- Implementing UseCases, Repositories, or DataSources
- Designing data flow between layers (domain, data, presentation)
- Setting up dependency injection with Koin or Hilt
- Working with Room, SQLDelight, or Ktor in a layered architecture
Module Structure
Recommended Layout
Dependency Rules
Critical: domain must NEVER depend on data, presentation, or any framework. It contains pure Kotlin only.
Domain Layer
UseCase Pattern
Each UseCase represents one business operation. Use operator fun invoke for clean call sites:
Domain Models
Domain models are plain Kotlin data classes — no framework annotations:
Repository Interfaces
Defined in domain, implemented in data:
Data Layer
Repository Implementation
Coordinates between local and remote data sources:
Mapper Pattern
Keep mappers as extension functions near the data models:
Room Database (Android)
SQLDelight (KMP)
Ktor Network Client (KMP)
Dependency Injection
Koin (KMP-friendly)
Hilt (Android-only)
Error Handling
Result/Try Pattern
Use Result<T> or a custom sealed type for error propagation:
Convention Plugins (Gradle)
For KMP projects, use convention plugins to reduce build file duplication:
Apply in modules:
Anti-Patterns to Avoid
- Importing Android framework classes in
domain— keep it pure Kotlin - Exposing database entities or DTOs to the UI layer — always map to domain models
- Putting business logic in ViewModels — extract to UseCases
- Using
GlobalScopeor unstructured coroutines — useviewModelScopeor structured concurrency - Fat repository implementations — split into focused DataSources
- Circular module dependencies — if A depends on B, B must not depend on A
References
See skill: compose-multiplatform-patterns for UI patterns.
See skill: kotlin-coroutines-flows for async patterns.


