skip to content

kotlin-reflect Dependency & Cost

Full reflection requires the separate kotlin-reflect artifact, which is large and adds startup cost, while plain ::class works without it. Interviewers ask because dragging kotlin-reflect into an Android or serverless build is a real, measurable mistake.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

questions

5

In Kotlin, what does the built-in standard library give you for reflection out of the box, and when do you need to add the kotlin-reflect dependency?

level: juniorimportance: must knowfreq 55%

answer

  1. ::class works; full reflection needs the JAR
  2. org.jetbrains.kotlin:kotlin-reflect
  3. KotlinReflectionNotSupportedError when missing
  4. kotlin.reflect.full package = the rich API
  5. Spring/Jackson pull it in transitively

basics

~10 s

Basic things like ::class work without extra setup. Richer reflection (reading properties, functions, parameters, supertypes) needs the separate kotlin-reflect library added to your build.

solid answer

~30 s

The kotlin-stdlib ships a tiny built-in reflection surface: the ::class operator gives you a KClass, but on stdlib alone you can mostly only read simpleName/qualifiedName and do basic identity/cast checks. Anything richer — listing members (memberProperties, declaredFunctions), reading constructors, supertypes, visibility, calling members, mapping a KClass to its Java counterpart fully, createInstance() — lives in the org.jetbrains.kotlin:kotlin-reflect artifact. You add it explicitly (e.g. implementation("org.jetbrains.kotlin:kotlin-reflect")). At runtime, calling a full-reflection API without kotlin-reflect on the classpath throws KotlinReflectionNotSupportedError. Many frameworks (Spring, Jackson Kotlin module) pull it in transitively, which is why people forget it is a separate dependency.

code

kotlin · 12 lines
kotlin
import kotlin.reflect.full.memberProperties

data class User(val id: Long, val name: String)

fun main() {
    // Works without kotlin-reflect:
    println(User::class.simpleName)        // "User"

    // Requires kotlin-reflect on the classpath, else
    // KotlinReflectionNotSupportedError at runtime:
    User::class.memberProperties.forEach { println(it.name) }
}

go deeper

for a junior

Knows ::class works out of the box and that a separate library is needed for 'more'.

for a middle

Names org.jetbrains.kotlin:kotlin-reflect and the kotlin.reflect.full APIs that require it.

for a senior

Explains the runtime KotlinReflectionNotSupportedError and how frameworks pull the artifact in transitively.

for a principal

Frames the two-JAR split as a deliberate cost-isolation design and reasons about when to keep reflection out entirely.

## Two reflection surfaces in Kotlin Kotlin splits reflection into two layers shipped in two different JARs: - **kotlin-stdlib** (always present): a minimal built-in reflection surface. The `::class` operator and `KClass` type live here, but only a thin slice of `KClass` actually works without the full library. - **kotlin-reflect** (`org.jetbrains.kotlin:kotlin-reflect`): the *full* implementation that backs the rich `kotlin.reflect.full` and `kotlin.reflect.jvm` APIs. ## What `::class` gives you without kotlin-reflect The `::class` operator (e.g. `String::class` or `value::class`) returns a `KClass<T>`. On stdlib alone you can reliably use: - `simpleName`, `qualifiedName` - `isInstance(obj)` - `.java` to bridge to a `java.lang.Class` (for plain Java reflection) ```kotlin val k: KClass<String> = String::class // works on stdlib alone println(k.simpleName) // "String" println(k.java.name) // bridge to java.lang.Class ``` ## What requires kotlin-reflect The richer members live mostly in the `kotlin.reflect.full` package and on `KCallable`/`KProperty`: - `memberProperties`, `declaredMemberProperties`, `declaredFunctions` - `primaryConstructor`, `constructors`, `createInstance()` - `supertypes`, `isData`, `visibility`, `isSealed` - Calling a `KFunction`/`KProperty` reflectively via `.call(...)` / `.get(...)` If you call one of these and kotlin-reflect is **not** on the classpath, the runtime throws `kotlin.reflect.jvm.internal.KotlinReflectionNotSupportedError`. ## How to add it ```kotlin dependencies { implementation("org.jetbrains.kotlin:kotlin-reflect") } ``` Version is usually managed by the Kotlin Gradle plugin's BOM/alignment, so you should match it to your Kotlin compiler version. Note many libraries (Spring, Jackson's `jackson-module-kotlin`) already pull it in transitively. ## Why the split exists Full reflection metadata and machinery is large and has startup/size cost. Keeping it out of stdlib means the common case (no reflection, or only `::class` identity checks) stays lightweight.

  • What exact error do you get if you call memberProperties without kotlin-reflect?
    A KotlinReflectionNotSupportedError is thrown at runtime — it is an Error, not a checked exception, so it usually surfaces as a crash.
  • Why might it 'just work' in a Spring app even though you never added kotlin-reflect?
    Spring (and Jackson's Kotlin module) declare kotlin-reflect as a transitive dependency, so it ends up on the classpath without you adding it explicitly.

stdlib reflection is a name tag (who are you); kotlin-reflect is the full medical chart (every detail) — you only carry the chart when you need it.

saying these in an interview costs you the question

  • Thinking all of KClass works from stdlib alone
  • Claiming kotlin-reflect is bundled in kotlin-stdlib
  • Not knowing the missing-dependency failure is a runtime error
  • Confusing kotlin-reflect with Java's java.lang.reflect

context

open as a page

You only need to check an object's type and read its simple name. How do you do that without pulling in kotlin-reflect, and what exactly are the limits of ::class on stdlib alone?

level: middleimportance: should knowfreq 40%

basics

~10 s

Use ::class with simpleName/qualifiedName, isInstance, or the is operator — these work without kotlin-reflect. You only hit the wall when you want members, constructors, or supertypes.

open as a page

What are the concrete costs of depending on kotlin-reflect — binary size, startup, and runtime — and how do you reason about them?

level: middleimportance: should knowfreq 45%

basics

~10 s

kotlin-reflect adds several megabytes to your app, makes startup a bit slower the first time you reflect, and each reflective lookup is much slower than a direct call. Use it sparingly and cache results.

open as a page

A teammate adds kotlin-reflect manually and pins it to a version different from the Kotlin compiler. What can go wrong, and how should the kotlin-reflect version be managed in a Gradle build?

level: seniorimportance: should knowfreq 30%

basics

~10 s

kotlin-reflect must match your Kotlin compiler version. A mismatch can cause incompatible-metadata warnings or runtime failures. Let the Kotlin Gradle plugin manage the version instead of hardcoding one.

open as a page

Your service's hot path uses kotlin-reflect to map data objects, and it's both slow and bloating the deployable. As a senior/principal, how do you decide whether to keep reflection, cache it, or eliminate the dependency entirely?

level: principalimportance: nice to knowfreq 22%

basics

~20 s

Measure first. If reflection is only used a little, cache the resolved handles. If it's on a hot path or you're size-constrained, replace it with compile-time code generation so you can drop the library entirely.

open as a page