← thecodex.expert · The Codex Family of Knowledge

Free · No account · Official sources only

Kotlin — Cradle to Mastery

A complete, structured path through Kotlin — from JetBrains' own frustration with Java to null safety, coroutines, and the Compose/Multiplatform reach that made it Google's preferred Android language and a genuine cross-platform option beyond it. Every lesson points at reference pages already written and verified on this site. Free, no account, no sign-up.

30 lessons 6 stages ~22 hours of reading 10 projects Kotlin 2.x (K2 compiler) · curriculum current as of 2026
Start Lesson 1 → Browse the reference instead

How this course works

1
Follow the stages in orderEach stage assumes the one before it. Stage 3 in particular assumes Stage 2 cold.
2
Read the tab the lesson namesReference pages have Beginner, Intermediate and Expert tabs. Read only what the lesson asks for on a first pass.
3
Run every exampleKeep the playground open in a second tab. Reading code you have not run is how misunderstandings survive.
4
Build after each stageDo not save all ten projects for the end. Pick one up as soon as a stage gives you enough to attempt it.
Casual pace: ~10 weeks at 4 hours a week
Steady pace: ~5 weeks at 8 hours a week
Intensive: ~2 weeks full-time
STAGE 0

Before You Start

Built by JetBrains to fix what its own engineers found frustrating about Java, then adopted by Google as Android's preferred language. These two lessons explain why, and get a compiler installed.

LESSON 1

What is Kotlin?

JetBrains built it to fix what its own engineers found frustrating about Java

Kotlin began as JetBrains' own internal answer to Java's friction points — verbosity, null pointer exceptions, checked exceptions — before Google made it Android's officially preferred language in 2019. That origin as a dogfooded internal tool, not a research project, explains why so much of Kotlin reads as pragmatic fixes rather than academic experiments.

📚 🟩 Read the Beginner tab only.
Key focus: Why Kotlin's origin as JetBrains' own fix for Java's pain points shapes its pragmatic design.
⏱ 30 min
Required Reading
→
What is Kotlin? — The Codex

Kotlin's origin at JetBrains, Google's 2019 Android endorsement, and where Kotlin 2.x's K2 compiler sits today.

LESSON 2

Setup and Compiler

kotlinc compiles standalone files — but real projects almost always use Gradle

<code>kotlinc</code> can compile a standalone <code>.kt</code> file directly from the command line for learning and small scripts, but any real Kotlin project — especially Android or multiplatform work — reaches for Gradle instead, which this course covers later in the Build Tools lesson.

📚 🟩 Read the Beginner tab only.
Key focus: Compiling a first file with kotlinc directly, and knowing why real projects move to Gradle quickly.
⏱ 30 min
Required Reading
→
Setup and Compiler — The Codex

Installing kotlinc, compiling and running a first .kt file, and IDE setup (IntelliJ IDEA / Android Studio).

STAGE 1

Language Fundamentals

The syntax and object model you will use in nearly every file: variables, control flow, functions, classes, interfaces, and the companion-object replacement for Java's static. Six lessons before Kotlin's type system properly begins.

LESSON 3

Variables and Types

val makes a reference immutable — and it's the default nearly everyone reaches for first

Kotlin's <code>val</code> declares an immutable reference and <code>var</code> a reassignable one, with <code>val</code> treated as the idiomatic default nearly everywhere — a small syntactic nudge toward immutability that shapes how most real Kotlin code actually gets written.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: Why val is the default reach, and when var is the genuinely correct choice instead.
⏱ 30 min
Required Reading
→
Variables and Types — The Codex

val vs. var, Kotlin's basic types, type inference, and string templates.

LESSON 4

Control Flow

if is an expression, not just a statement — and when replaces switch with genuinely more power

Kotlin's <code>if</code> can be used as an expression that directly produces a value, not merely a branching statement, and <code>when</code> replaces <code>switch</code> with real added power — matching ranges, types, and arbitrary boolean conditions, not just equality against a constant.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: Using if and when as expressions, and the extra matching power when has over a C-style switch.
⏱ 45 min
Required Reading
→
Control Flow — The Codex

if/else as both statement and expression, when's range/type/arbitrary-condition matching, and for/while loops.

LESSON 5

Functions

Default parameter values and named arguments remove most of the need for overloading

Default parameter values combined with named arguments cover most of the situations Java would force you to solve with method overloading — one function signature handles many call shapes, and named arguments make a call with several optional parameters genuinely readable at the call site.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: How default parameters and named arguments together remove most of Java's reasons to overload a method.
⏱ 45 min
Required Reading
→
Functions — The Codex

Function syntax, default parameter values, named arguments, single-expression functions, and top-level functions.

LESSON 6

Classes and Objects

Every Kotlin class is final by default — the opposite of Java

A Kotlin class cannot be subclassed unless it is explicitly marked <code>open</code> — the exact opposite of Java's default. This is a deliberate design decision favoring composition and explicit intent over accidental, unplanned inheritance hierarchies.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: Why final-by-default is a deliberate design choice, not an oversight, and what open buys back.
⏱ 45 min
Required Reading
→
Classes and Objects — The Codex

Class declarations, primary and secondary constructors, properties with custom getters/setters, and the open keyword.

LESSON 7

Interfaces

Default method bodies from day one — a feature Java didn't get until version 8

Kotlin interfaces have supported default method implementations since the language's very first release, years before Java added the same capability in Java 8. This let Kotlin interfaces carry real shared behavior from the start, not just method signatures.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: Writing interfaces with real default behavior, and resolving conflicts when multiple interfaces collide.
⏱ 30 min
Required Reading
→
Interfaces — The Codex

Interface declarations, default method bodies, properties in interfaces, and resolving diamond conflicts between interfaces.

LESSON 8

Object Declarations

No static keyword at all — companion object is Kotlin's real, different answer

Kotlin has no <code>static</code> keyword whatsoever. A <code>companion object</code> — a real, singleton object tied to its class — is the language's actual, more principled answer to the class-level members Java's <code>static</code> provided, and <code>object</code> declarations cover the general singleton pattern beyond that.

📚 ⚡ Intermediate.
Key focus: Why companion object replaces static, and how object declarations give you a real singleton for free.
⏱ 30 min
Required Reading
→
Object Declarations — The Codex

object declarations for singletons, companion objects and their relationship to a class, and anonymous objects.

STAGE 2

Null Safety and Kotlin's Type System — Its Defining Discipline

This is the stage that makes Kotlin, Kotlin: a type system that makes null a compile-time fact instead of a runtime surprise, sealed hierarchies that make that safety exhaustive, and the data-modeling and composition tools built on top. Six lessons, the heart of the course.

LESSON 9

Null Safety and Types

Nullable types, the safe call, the Elvis operator, and smart casts

Kotlin's type system distinguishes <code>String</code> from <code>String?</code> at compile time, so the compiler — not a runtime crash — is what catches a missed null case. The safe call <code>?.</code>, the Elvis operator <code>?:</code>, and smart casts are the everyday tools built on top of that one distinction, with <code>!!</code> as the deliberately loud escape hatch.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: How String vs. String? turns null-handling into a compile-time-checked fact, not a runtime gamble.
⏱ 1 hours
Required Reading
→
Null Safety and Types — The Codex

Nullable types (String?), the safe call ?., the Elvis operator ?:, the non-null assertion !!, and smart casts after a null check.

LESSON 10

Sealed Classes

Every possible subtype restricted to one file — so when needs no else

A <code>sealed</code> class or interface restricts every one of its possible subtypes to living in the same file, which is exactly what lets the compiler verify a <code>when</code> expression over it has handled every case — no <code>else</code> branch required, and a new subtype added later breaks the build everywhere it should.

📚 ⚡ Intermediate.
Key focus: Why sealing a hierarchy is what lets the compiler prove a when expression is exhaustive.
⏱ 45 min
Required Reading
→
Sealed Classes — The Codex

sealed class and sealed interface declarations, exhaustive when expressions over them, and modeling state with sealed hierarchies.

LESSON 11

Data Classes

One keyword generates equals, hashCode, toString, copy, and destructuring

Declaring a class as <code>data class</code> generates <code>equals</code>, <code>hashCode</code>, <code>toString</code>, a <code>copy</code> function for immutable updates, and destructuring components — all derived automatically from the primary constructor's properties alone, eliminating a whole category of Java boilerplate in one keyword.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: What data class generates for free, and the primary-constructor convention that makes it possible.
⏱ 45 min
Required Reading
→
Data Classes — The Codex

data class syntax, generated equals/hashCode/toString/copy, destructuring declarations, and data class limitations (inheritance, var properties).

LESSON 12

Generics

out and in declared once at the class — no repeating extends/super at every call site

Kotlin lets you declare a generic type parameter's variance — <code>out</code> for producer-only, <code>in</code> for consumer-only — once, at the class declaration itself, replacing Java's need to repeat <code>? extends</code> or <code>? super</code> at every single call site that uses the type.

📚 ⚡ Intermediate.
Key focus: Declaration-site variance versus Java's use-site wildcards, and when out/in actually matter.
⏱ 45 min
Required Reading
→
Generics — The Codex

Generic classes and functions, declaration-site variance with out/in, type projections, and reified type parameters on inline functions.

LESSON 13

Delegation

The by keyword implements an entire interface by forwarding to another object

The <code>by</code> keyword lets a class implement an interface by forwarding every call to another object that already implements it — real composition, with almost none of the manual forwarding boilerplate that pattern would otherwise require. Property delegation (<code>by lazy</code> and friends) applies the same idea to individual properties.

📚 ⚡ Intermediate.
Key focus: How class delegation gives you composition without writing the forwarding methods by hand.
⏱ 45 min
Required Reading
→
Delegation — The Codex

Class delegation with by, property delegation (by lazy, by Delegates.observable), and writing a custom property delegate.

LESSON 14

Extension Functions

Add a method to String or any class — no inheritance, no modifying the source

An extension function lets you add what looks like a genuine new method to <code>String</code> or any existing class — including ones you don't own the source of — without inheritance and without touching the original class at all. It's resolved statically, which is the one real limitation worth understanding.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: How extension functions add methods to existing types, and why static resolution is the one catch.
⏱ 30 min
Required Reading
→
Extension Functions — The Codex

Extension function syntax, extension properties, static resolution (no real overriding), and idiomatic uses in the standard library.

STAGE 3

Functional Style and Collections

Lambdas as first-class values, the five scope functions everyone eventually reaches for, and how Kotlin models a collection's read-only view versus its actual mutability. Six lessons.

LESSON 15

Lambdas and Higher-Order Functions

A trailing lambda can move outside the parentheses entirely

When a lambda is a function's last parameter, Kotlin lets it move outside the parentheses entirely — the exact syntax trick behind every readable DSL-style Kotlin API, including the standard library's own scope functions and Gradle's Kotlin DSL.

📚 ⚡ Intermediate.
Key focus: How trailing-lambda syntax is the real mechanism behind Kotlin's readable DSL-style APIs.
⏱ 45 min
Required Reading
→
Lambdas and Higher-Order Functions — The Codex

Lambda syntax, function types, higher-order functions taking/returning functions, and trailing-lambda syntax.

LESSON 16

Scope Functions

let, run, with, apply, also — differing in exactly two ways

Kotlin's five scope functions — <code>let</code>, <code>run</code>, <code>with</code>, <code>apply</code>, <code>also</code> — differ from each other in exactly two dimensions: how you refer to the receiver inside the block (<code>it</code> vs. <code>this</code>), and what the whole expression returns (the receiver itself vs. the lambda's result). Once those two axes click, choosing between them stops being guesswork.

📚 ⚡ Intermediate.
Key focus: The two-axis mental model (receiver reference, return value) that distinguishes all five scope functions.
⏱ 45 min
Required Reading
→
Scope Functions — The Codex

let, run, with, apply, and also, compared on receiver access (it/this) and return value, with idiomatic use cases for each.

LESSON 17

Kotlin DSLs

Lambdas with a receiver are the exact mechanism behind build.gradle.kts

A lambda with a receiver — where the lambda body can call the receiver's members directly with no qualifier — is the precise language feature behind Gradle's own <code>build.gradle.kts</code> readable syntax, and the same technique is available to build your own internal DSLs.

📚 ⚡ Intermediate → 🔥 Expert.
Key focus: Building a small internal DSL using the same lambda-with-receiver mechanism Gradle's own DSL relies on.
⏱ 45 min
Required Reading
→
Kotlin DSLs — The Codex

Function types with a receiver, building a type-safe builder DSL, and why this is what makes Gradle's Kotlin DSL possible.

LESSON 18

Collections

List isn't necessarily immutable — it's a read-only VIEW

Kotlin's <code>List</code> interface is read-only, not necessarily immutable: the same underlying data might still be mutated through a different reference that holds it as a <code>MutableList</code>, so "read-only" and "immutable" are genuinely different guarantees worth telling apart.

📚 🟩 Beginner → ⚡ Intermediate.
Key focus: The real difference between a read-only view and a genuinely immutable collection.
⏱ 45 min
Required Reading
→
Collections — The Codex

List/MutableList, Set/MutableSet, Map/MutableMap, the read-only-view distinction, and common collection operations (map, filter, fold).

LESSON 19

Exception Handling

No checked exceptions at all — a deliberate rejection of a Java design

Kotlin has no checked exceptions whatsoever, a deliberate rejection of a Java design JetBrains considered, in practice, a failed experiment — one that pushed developers toward empty catch blocks and blanket <code>throws Exception</code> declarations more often than genuinely correct error handling.

📚 ⚡ Intermediate.
Key focus: Why JetBrains deliberately dropped checked exceptions, and what Kotlin uses instead to signal fallibility.
⏱ 30 min
Required Reading
→
Exception Handling — The Codex

try/catch/finally, try as an expression, the runCatching helper, and why Kotlin has no throws declarations to satisfy.

LESSON 20

Annotations

A property compiles to several JVM elements — use-site targets pick which one

A single Kotlin property can compile down to several distinct underlying JVM elements — a field, a getter, a setter, a backing field — and an annotation's use-site target (<code>@field:</code>, <code>@get:</code>, and so on) is how you tell the annotation processor exactly which one to attach to.

📚 ⚡ Intermediate → 🔥 Expert.
Key focus: Why one Kotlin property can need a use-site target to say which underlying JVM element an annotation attaches to.
⏱ 30 min
Required Reading
→
Annotations — The Codex

Annotation declarations, built-in annotations (@JvmStatic, @Deprecated), use-site targets, and how they interact with Java interop.

STAGE 4

Coroutines and Cross-Platform Kotlin

Asynchronous code without callback pyramids, structured concurrency's real guarantee, working alongside existing Java code, and how far a single Kotlin codebase can actually reach across platforms. Five lessons.

LESSON 21

Coroutines and Flow

suspend functions, launch, async/await, and Flow for reactive streams

Coroutines let you write sequential-looking code for genuinely asynchronous work — <code>suspend</code> functions, <code>launch</code> for fire-and-forget work, <code>async</code>/<code>await</code> for a result you need back — and <code>Flow</code> extends the same idea to a stream of values arriving over time rather than a single result.

📚 ⚡ Intermediate.
Key focus: Writing sequential-looking async code with suspend functions, and when Flow fits instead of a single result.
⏱ 1 hours
Required Reading
→
Coroutines and Flow — The Codex

suspend functions, launch and async/await, CoroutineScope and CoroutineContext, and an introduction to Kotlin Flow.

LESSON 22

Coroutines Deep Dive

A parent coroutine cannot complete until every child it launched has finished

Structured concurrency is coroutines' real safety guarantee: a parent coroutine genuinely cannot complete until every child coroutine it launched has itself finished, which is exactly what prevents orphaned background work from silently outliving the scope that was supposed to own it.

📚 ⚡ Intermediate → 🔥 Expert.
Key focus: Why structured concurrency's parent-waits-for-children rule is what prevents orphaned background work.
⏱ 1 hours
Required Reading
→
Coroutines Deep Dive — The Codex

Structured concurrency guarantees, coroutine cancellation and cooperative checks, exception handling across coroutines, and Dispatchers.

LESSON 23

Kotlin and Java Interop

Platform types are Kotlin's honest acknowledgment it can't verify Java's nullability

Calling Java code from Kotlin opens a genuine hole in null-safety, since Java declares no nullability information the Kotlin compiler can check. Platform types (shown as <code>String!</code>) are Kotlin's honest, visible acknowledgment of exactly that gap, rather than a false promise of safety Kotlin can't actually back up.

📚 ⚡ Intermediate.
Key focus: Why platform types exist, and the discipline they require when Kotlin calls untyped-for-null Java code.
⏱ 45 min
Required Reading
→
Kotlin and Java Interop — The Codex

Calling Java from Kotlin and vice versa, platform types, @JvmStatic/@JvmOverloads for cleaner Java-facing APIs, and interop gotchas.

LESSON 24

Kotlin Multiplatform

expect declares what every platform must provide — actual fills it in

Kotlin Multiplatform's <code>expect</code>/<code>actual</code> mechanism lets shared code declare what every target platform must provide, while each platform's own module supplies its own real implementation — sharing business logic across Android, iOS, and other targets without sharing what genuinely has to differ per platform.

📚 ⚡ Intermediate → 🔥 Expert.
Key focus: How expect/actual lets shared code demand a platform-specific implementation without dictating it.
⏱ 45 min
Required Reading
→
Kotlin Multiplatform — The Codex

expect/actual declarations, common vs. platform-specific source sets, and what Kotlin Multiplatform is and isn't good for sharing.

LESSON 25

Kotlin/Native

No JVM, no bytecode — compiles straight to a native binary via LLVM

Kotlin/Native compiles Kotlin code directly to a native binary through LLVM, with no JVM and no bytecode involved at all — which is precisely why it exists: it's what lets Kotlin Multiplatform actually target iOS, where there is no JVM to run bytecode on in the first place.

📚 🔥 Expert.
Key focus: Why Kotlin/Native's LLVM-based, JVM-free compilation is specifically what makes iOS targeting possible.
⏱ 45 min
Required Reading
→
Kotlin/Native — The Codex

Kotlin/Native's LLVM-based compilation model, memory management differences from the JVM, and its role in targeting iOS.

STAGE 5

Tooling, Testing and Modern Kotlin

What surrounds the code: build tools, testing frameworks, Compose's declarative UI model, and a final lesson tying the standard library's idioms together. Five lessons to close out the course.

LESSON 26

Build Tools

Gradle's Kotlin DSL gets full IDE autocomplete on your build file itself

Gradle's Kotlin DSL (<code>build.gradle.kts</code>) gets full IDE autocomplete and compile-time type checking directly on your build script — something the older Groovy DSL, being dynamically typed, could never genuinely offer.

📚 ⚡ Intermediate.
Key focus: Why the Kotlin DSL's type-checked build files are a real upgrade over Groovy's, not just a syntax swap.
⏱ 45 min
Required Reading
→
Build Tools — The Codex

build.gradle.kts structure, dependency declarations, common plugins, and the Kotlin DSL's IDE-support advantage over Groovy.

LESSON 27

Testing

kotlin.test wraps JUnit — Kotest goes further with its own expressive DSL

<code>kotlin.test</code> is a thin, Kotlin-friendly, multiplatform-compatible wrapper directly over JUnit's assertions, while Kotest goes considerably further with a genuinely different, more expressive testing DSL of its own — worth knowing both, since real Kotlin codebases use either.

📚 ⚡ Intermediate.
Key focus: Choosing between kotlin.test's thin JUnit wrapper and Kotest's own more expressive DSL.
⏱ 45 min
Required Reading
→
Testing — The Codex

kotlin.test annotations and assertions, Kotest's DSL style, and multiplatform testing considerations.

LESSON 28

Jetpack Compose Basics

No XML layouts — Compose describes UI as a function of state

Jetpack Compose replaces Android's traditional XML layouts and <code>findViewById</code> calls entirely: a composable function describes the UI as a direct function of the current state, and Compose automatically re-runs that function whenever the state it reads actually changes.

📚 ⚡ Intermediate.
Key focus: The UI-as-a-function-of-state model, and how Compose knows when to automatically re-run a composable.
⏱ 45 min
Required Reading
→
Jetpack Compose Basics — The Codex

@Composable functions, state with remember/mutableStateOf, recomposition, and basic layout composables (Column, Row, Box).

LESSON 29

Standard Library Deep Dive

map and filter are eager — each step builds a full new list

Kotlin's everyday collection operations like <code>map</code> and <code>filter</code> are eager by default — each step in a chain builds a complete new list immediately, even when you only actually need the first matching result — which is exactly the case <code>sequences</code> exist to handle lazily instead.

📚 ⚡ Intermediate → 🔥 Expert.
Key focus: Why eager collection chains can do unnecessary work, and when a sequence is the genuinely correct fix.
⏱ 45 min
Required Reading
→
Standard Library Deep Dive — The Codex

Eager vs. lazy evaluation, Sequence and its lazy chain semantics, and choosing between a List chain and a Sequence chain.

LESSON 30

Kotlin Idioms, Tied Together

Data classes, extension functions, scope functions, collections and destructuring together

This lesson is the course's synthesis and capstone: data classes, extension functions, the five scope functions, the collections API, and destructuring declarations &mdash; the individual features from across this entire course, seen together as the actual idiomatic style real Kotlin codebases are written in, not just a list of language features in isolation.

📚 ⚡ Intermediate.
Key focus: Seeing data classes, extension functions, scope functions, collections and destructuring work together as one idiomatic style.
⏱ 1.25 hours
Required Reading
→
Kotlin Idioms, Tied Together — The Codex

Data classes, extension functions, scope functions (let/run/apply/also/with), the collections API, and destructuring declarations, together.

STAGE 6

Concepts That Cross Languages

These pages explain ideas that are not specific to Kotlin — they apply to every language you will ever learn. Read them once and the next language costs you far less effort. They pair well with the lessons above rather than replacing them.

STAGE 7

Build Real Things — 10 Projects

Reading is not enough. These 10 projects — five basic, five medium — are chosen because each one exercises something specific you learned above, and because they are genuinely idiomatic Kotlin rather than generic exercises. Each link below opens the project brief; the Kotlin implementation walkthrough is in progress.

BASIC — 5 PROJECTS
→
Number Guessing Game

readLine() input parsing, a guess loop, and kotlin.random.Random for the secret number.

→
Temperature Converter

A when expression for the conversion direction, and string templates for formatted output.

→
Word Counter

Reading a file with File(...).readText(), and a mutableMapOf<String,Int> for a frequency table.

→
To-Do List (CLI)

A data class for the task shape, and hand-rolled line-based persistence.

→
Password Generator

A sealed class or enum for character-set options, and SecureRandom via Java interop for real unpredictability.

MEDIUM — 5 PROJECTS
→
Web Scraper

java.net.http's HttpClient via Java interop, and Kotlin's regex support for link extraction.

→
REST API

com.sun.net.httpserver's built-in HttpServer via interop, with sealed classes for typed responses.

→
CLI Task Manager

A sealed class for subcommands, and an exhaustive when expression the compiler checks for completeness.

→
URL Shortener

A thread-safe ConcurrentHashMap-backed store, and coroutines serving the HTTP handler.

→
Log Analyser

Sequences for parsing and aggregating semi-structured lines without building intermediate lists.

STAGE 8

Practice & Experimentation

Ongoing, not a final step. Use these throughout the course — try every snippet you read, and run anything you are unsure about rather than assuming.

Resources
→
Kotlin Playground

Run Kotlin code without installing anything, via the official Kotlin Playground.

→
Kotlin Snippets

Copy-ready idiomatic patterns to keep beside you while you build.

→
Kotlin Reference Hub

All 30 topic pages in one index, for looking things up later.