Skip to content
Now building for 2026 — tell us what your team needs. Start a project
Sembosi Digital Sembosi Digital

Kotlin or Java for a New Android App

Android 2 min read
Kotlin or Java for a New Android App

A practical decision framework for choosing the language of a new Android project — based on team, codebase and lifetime of the app.

The honest answer is that both work. But "both work" is not a decision, so here is how we think about it when a client asks.

Kotlin is the default for new work

Since Google announced Kotlin-first development, the platform's direction has been clear: new APIs, samples and tooling target Kotlin. Coroutines make asynchronous work — network calls, database access — dramatically simpler than the callback and thread patterns Java requires.

suspend fun loadPatient(id: String): Patient = withContext(Dispatchers.IO) {
    api.getPatient(id)
}

Null safety alone removes an entire category of crashes. In Java, every reference is a potential NullPointerException; in Kotlin, the type system tells you which values can be null and forces you to handle them.

When Java still makes sense

  • An existing large Java codebase. A rewrite for the sake of language preference is expensive and risky. Kotlin interoperates with Java, so new modules can be Kotlin while legacy code stays Java.
  • A team that only knows Java. Tooling is not the bottleneck; people are. A team writing idiomatic Kotlin beats a team forcing Kotlin.
  • Very long-lived apps with old toolchains. Some enterprise environments lag on Gradle and library versions.

What we actually recommend

For a new Android application in 2026, start with Kotlin, use Jetpack libraries, and keep the architecture boring: a single-activity app, ViewModel for state, Room for local storage, Retrofit or Ktor for the API, and coroutines for concurrency.

class PatientViewModel(private val repo: PatientRepository) : ViewModel() {
    private val _state = MutableStateFlow(PatientUiState())
    val state: StateFlow<PatientUiState> = _state.asStateFlow()

    fun load(id: String) = viewModelScope.launch {
        _state.update { it.copy(loading = true) }
        runCatching { repo.getPatient(id) }
            .onSuccess { patient -> _state.update { it.copy(loading = false, patient = patient) } }
            .onFailure { error -> _state.update { it.copy(loading = false, error = error.message) } }
    }
}

That structure survives staff changes, survives Android version changes, and is straightforward to test.

The part that matters more than the language

Neither Kotlin nor Java will save a badly designed app. Decide the offline strategy, the sync model and the API contract before you write the first screen — those decisions are far more expensive to change later than the language you typed them in.

If you are building a pharmacy counter app that must keep working when the network drops, that design problem is the real project. The language is just how you express the answer.