Kotlin is a statically typed programming language from JetBrains that runs on the JVM, works with every Java library, and can share one codebase across Android, iOS, desktop and the web. It gives you most of Java's reach with less code and a compiler that stops whole classes of bugs before the program ever runs.
What Kotlin is
JetBrains, the company behind IntelliJ IDEA, designed Kotlin as a more concise and safer alternative to Java that still fitted into existing Java projects. Google made it an officially supported Android language in 2017 and has recommended it as the first choice for Android since 2019, but Google adopted Kotlin rather than creating it.
'Statically typed' means every value has a type the compiler knows before the program runs. You don't have to write most of those types yourself, though: Kotlin infers them.
val name = "Kitty" // inferred as String
var tuna = 3 // inferred as Int
tuna += 1 // fine: var can change
// name = "Tom" // error: val can't be reassignedval is a read-only reference and var is one you can reassign. Reaching for val by default makes code easier to reason about, because a value that can't change can't surprise you later.
One language, several compilers
Kotlin has no single runtime of its own. The compiler has several back ends, and each turns the same language into something a different platform runs:
- Kotlin/JVM compiles to JVM bytecode, the same format Java compiles to. Servers, desktop apps and Android builds take this route.
- Kotlin/Native compiles to machine code, which is how Kotlin reaches iOS and other places with no JVM.
- Kotlin/JS and Kotlin/Wasm compile for the browser.
This is why the same language can sit behind a backend service, an Android app and an iOS app at once.
Working with Java
Because Kotlin/JVM produces ordinary JVM bytecode, Kotlin and Java classes can live in the same project and call each other directly. There is no wrapper layer or conversion step: a Java library is just a library.
import java.time.LocalDate
val today = LocalDate.now()
val bowls = java.util.ArrayList<String>()
bowls.add("tuna")
println("$today: $bowls")That matters in practice. A team with a large Java codebase can write new files in Kotlin and leave the old ones alone, and a Kotlin project can use decades of mature JVM libraries, from database drivers to Spring Boot, from the first day.
Less code for the same job
Much of Kotlin's appeal is how little ceremony it needs. A class that only holds data is one line:
data class Cat(val name: String, val tuna: Int)
val kitty = Cat("Kitty", 3)
val fed = kitty.copy(tuna = kitty.tuna + 1)
println(fed) // Cat(name=Kitty, tuna=4)The data keyword generates equals, hashCode, toString and copy for you. In older Java you would write or generate all of those by hand, and then keep them in sync every time a field changed. Default arguments, named arguments, extension functions and string templates such as "$today" cut boilerplate in the same way.
Less code isn't only about typing less. Every line you don't write is a line nobody has to review, test or keep correct.
A compiler that catches mistakes early
Kotlin's type system is designed to turn common runtime crashes into compile errors, so you find them while writing the code rather than when a user does.
Null safety
In Kotlin a type can't hold null unless you say so with a ?. The compiler then makes you deal with the missing case before you use the value:
var nickname: String? = null
// println(nickname.length) // doesn't compile
println(nickname?.length) // null
println(nickname?.length ?: 0) // 0?. is a safe call: it returns null instead of crashing when the left side is null. ?:, the Elvis operator, supplies a fallback. The null pointer exception that haunts so much Java code becomes something the compiler points at, with a line number.
Exhaustive when
A sealed type lists every possible subtype up front, and a when over it must handle them all:
sealed interface Order
data class Paid(val amount: Int) : Order
data object Cancelled : Order
fun describe(o: Order): String = when (o) {
is Paid -> "Paid ${o.amount}"
Cancelled -> "Cancelled"
}Add a Refunded subtype later and every when that forgot it stops compiling. The compiler hands you a list of the places to update, instead of leaving one to fail quietly in production.
Letting AI draft, letting the compiler check
A strict compiler pairs well with AI coding assistants. The assistant writes a first draft quickly; the compiler then checks it against the types, nullability and exhaustive when rules above. A draft that calls a method that doesn't exist, passes a String where an Int belongs or ignores a possible null is rejected straight away, and the error message tells you, or the assistant, exactly where.
Be clear about what that check covers. The compiler proves the code is consistent with its types. It can't tell whether the logic is what you meant: a function that adds when it should subtract compiles perfectly well. Code that compiles still needs reading and tests, whoever wrote it.
One codebase with Kotlin Multiplatform
Most apps that ship on several platforms contain the same logic more than once: the same API calls, validation rules and data models, written in Kotlin for Android and again in Swift for iOS. Kotlin Multiplatform (KMP) lets you write that shared code once in Kotlin and compile it for each platform you target.
Sharing is a dial, not a switch. A team can start with only its networking and data layer shared and a native UI on each platform, then move more across later. Compose Multiplatform, JetBrains' UI framework, goes further and shares the UI too. Each app can still keep native code for anything truly platform-specific, such as the camera. The Kotlin Quiz page covers KMP's project structure, source sets and libraries in detail.
What you can build with it
- Android apps, where Kotlin is the default choice.
- iOS apps, sharing logic (and optionally UI) through KMP.
- Backend services and APIs, with Ktor, JetBrains' own framework, or Spring Boot, which supports Kotlin directly.
- Desktop apps, with Compose Multiplatform on the JVM.
- Web apps, through Kotlin/JS or Kotlin/Wasm.
- Command-line tools and scripts, on the JVM or as native binaries.
That range is why Kotlin suits a solo developer who wants one language for everything as well as a large company that wants to share code between teams.
When it fits, and what it costs
Kotlin is a strong fit for Android work, for new JVM services, for Java codebases that want a gentler modern language, and for teams that want to stop writing the same logic twice across mobile platforms.
It has costs worth knowing:
- Build times. Large Kotlin projects built with Gradle can be slow to compile, so incremental builds and build caching matter.
- Multiplatform libraries. Shared code can only use libraries that support every target you build for. The JVM ecosystem is huge; the multiplatform part of it is smaller.
- iOS still needs Apple's tools. Building for iOS needs a Mac with Xcode, even when the code is Kotlin.
- Team skills. A team fluent in Swift or TypeScript has a language to learn, and KMP adds Gradle to the iOS side of the project.
Common mistakes
- Reaching for
!!. The not-null assertionx!!tells the compiler to trust you, and throws if you were wrong. Scattering it around brings back the crashes null safety removes. Prefer?.,?:or an early return. - Trusting Java's nulls. Kotlin can't know whether a Java method returns
null, so it lets you choose. Declare the result as nullable, such asval dir: String? = System.getenv("TUNA_DIR"), unless the Java side guarantees a value. - Writing Java in Kotlin syntax. Mutable
vars everywhere and hand-written getters miss what the language gives you. Default tovaland data classes. - 'It compiles, so it works.' Especially with AI-written code, the compiler is the first check, not the last.
Key takeaways
- Kotlin is a statically typed language from JetBrains, and Google's recommended language for Android.
- Kotlin/JVM compiles to the same bytecode as Java, so the two mix freely and share libraries.
- Null safety and exhaustive
whenturn common runtime crashes into compile errors. - The compiler is a fast check on AI-drafted code, but not a substitute for review and tests.
- Kotlin Multiplatform shares one codebase across Android, iOS, desktop and the web, as much or as little as you choose.