Tooling & Build
How Kotlin projects are built: the Gradle Kotlin DSL, annotation processing with kapt and KSP, compiler options and plugins, opt-in for experimental APIs, and the linters that gate a build. Interviewers use this to gauge how much real project setup you have done.
part ofKotlinoverview, primer and where to startread it →on this pageshowhide
explore
- How Kotlin Does Build Tooling5 questions
- Gradle Kotlin DSL20 questions
- build.gradle.kts Basics5 questions
- plugins {} Block & Version Catalogs5 questions
- Kotlin Gradle Plugin Config5 questions
- Multiplatform Gradle Setup5 questions
- Annotation Processing20 questions
- kapt (Legacy)5 questions
- KSP (Kotlin Symbol Processing)5 questions
- KSP vs kapt Tradeoffs5 questions
- Common Processors (Room/Dagger/Moshi)5 questions
- Compiler25 questions
- Compiler Options & jvmTarget5 questions
- K2 Compiler Overview5 questions
- Compiler Plugins: all-open / no-arg5 questions
- kotlinx.serialization Plugin5 questions
- @OptIn / @RequiresOptIn5 questions
- Quality Tooling21 questions
- ktlint5 questions
- detekt6 questions
- Explicit API Mode5 questions
- Binary Compatibility Validator5 questions
questions
91 · 5 sectionsWhat actually turns your Kotlin source into runnable artifacts, and what role does Gradle (or Maven) play in that process?
basics
~20 sThe Kotlin compiler, kotlinc, turns your .kt files into class files. Gradle or Maven is the build tool that calls the compiler for you, downloads libraries, and packages the output. The build tool drives the compiler.
Why does Kotlin recommend KSP over kapt for annotation processing, and how do they differ mechanically?
basics
~20 sBoth generate code at build time from annotations. kapt fakes Java stubs so old Java annotation processors work, which is slow. KSP reads Kotlin code directly through a lightweight API, so it is much faster and understands Kotlin features properly.
What is Kotlin's opt-in mechanism for experimental APIs (e.g. @OptIn / @RequiresOptIn), and how do you satisfy it at call sites and project-wide?
basics
~20 sSome Kotlin APIs are marked as experimental and may change. The compiler forces you to explicitly acknowledge that risk before using them — either by adding @OptIn at the call site or by enabling the opt-in for the whole module in the build file.
Kotlin libraries often prefer compile-time codegen (KSP / compiler plugins) over runtime reflection. What are the engineering trade-offs of that choice?
basics
~20 sGenerating code while building makes the program start faster, run faster, and catch mistakes early because everything is decided at compile time. Reflection is more flexible and needs no extra tooling, but is slower at runtime and harder to optimize, especially for native or small binaries.
How do Kotlin compiler plugins differ from KSP/kapt symbol processors, and what can a compiler plugin do that a processor cannot? Give examples.
basics
~20 sSymbol processors can only read your code and generate new files. Compiler plugins hook inside the compiler and can change the actual bytecode of existing code — adding methods, rewriting bodies, or generating synthetic members. They are more powerful but more invasive.
What is the difference between build.gradle and build.gradle.kts, and what do you gain by choosing the Kotlin DSL?
basics
~10 sbuild.gradle uses the Groovy language; build.gradle.kts uses Kotlin. The Kotlin version is type-checked, so the IDE gives autocompletion, error highlighting, and reliable refactoring before you run the build.
How do you enable Kotlin/JVM compilation in a Gradle Kotlin DSL build, and what does applying the Kotlin Gradle Plugin actually give you?
basics
~10 sAdd the Kotlin JVM plugin in the plugins block of build.gradle.kts. That tells Gradle to compile your .kt files, sets up source folders, and adds the Kotlin standard library automatically.
In a Kotlin Multiplatform build, how do you apply the plugin and declare which platforms (targets) your library should compile for?
basics
~10 sApply the kotlin("multiplatform") plugin, then inside the kotlin { } block call functions like jvm(), js(), and a native target such as linuxX64(). Each call adds a platform you compile for.
What is the Gradle `plugins {}` block in a `build.gradle.kts` file, and how does it differ from the older `apply plugin` approach?
basics
~20 sThe plugins {} block is where you list the build plugins a project uses, each by an id and optional version. It is the modern, recommended way and lets Gradle resolve and apply plugins efficiently.
What are 'type-safe accessors' in the Gradle Kotlin DSL, where do they come from, and why might one suddenly be unavailable?
basics
~20 sType-safe accessors are generated, strongly typed shortcuts—like a java {} block or an implementation(...) configuration—that appear after a plugin is applied. They give autocompletion and compile checks. They disappear when Gradle cannot see the plugin at configuration time.
You're adding Room to a Kotlin module. Which Gradle dependency configuration do you use to wire up Room's annotation processor, and what else must you add to the build?
basics
~20 sYou add the Room library as a normal dependency, and put Room's compiler on the ksp configuration (the modern way) instead of a plain dependency. You also apply the KSP Gradle plugin so ksp(...) exists.
What is kapt and what problem does the kotlin-kapt Gradle plugin solve for Kotlin projects?
basics
~20 skapt is a Kotlin plugin that lets old Java annotation-processing tools (like Dagger or Room) work on Kotlin code. It does this by first turning Kotlin into simple Java placeholder files those tools can read.
Why is KSP generally faster than kapt for annotation processing in a Kotlin project?
basics
~10 skapt first turns your Kotlin into fake Java code so old Java tools can read it, which is slow. KSP reads your Kotlin code directly, skipping that extra step, so the build is faster.
What is KSP (Kotlin Symbol Processing), and what are the two entry-point types a processor author must implement?
basics
~10 sKSP is Kotlin's tool for reading code at compile time and generating new source files. You write a SymbolProcessor that does the work, and a SymbolProcessorProvider that creates it.
Walk through configuring kapt for a Java annotation processor in a Gradle Kotlin DSL build, including how processor arguments are passed.
basics
~10 sApply the kotlin-kapt plugin, then add the processor with the kapt(...) line instead of implementation(...). If the processor needs options, pass them in a kapt { arguments { arg(...) } } block.
What does the Kotlin compiler's jvmTarget option control, and what happens if you target a higher bytecode version than the JDK that actually runs your app?
basics
~10 sjvmTarget sets which Java bytecode version the compiler produces, like 17 or 21. If you produce bytecode newer than the JVM running it, the app fails to start with an UnsupportedClassVersionError.
Kotlin classes are final by default. Why does that break Spring and JPA, and what compiler plugins solve it?
basics
~20 sKotlin classes can't be subclassed unless you write 'open'. Spring and Hibernate need to subclass your classes to add behavior. The all-open and no-arg plugins make the needed classes open and give them an empty constructor automatically.
What is the K2 compiler in Kotlin, and since which version is it the stable default?
basics
~10 sK2 is a rewritten Kotlin compiler frontend. It understands your code faster and more consistently. It became the stable default starting with Kotlin 2.0.
What is the opt-in mechanism in Kotlin, and how do you consume an experimental API like ExperimentalCoroutinesApi?
basics
~10 sSome Kotlin APIs are marked experimental and may change. The compiler warns or errors when you use them. To say 'I accept the risk', you add @OptIn(TheMarker::class) above your function or class.
How do you enable kotlinx.serialization in a Kotlin Gradle project, and what two pieces do you need besides the @Serializable annotation?
basics
~10 sAdd the serialization compiler plugin in the Gradle plugins block and add the runtime library as a dependency. Then mark classes with @Serializable.
What is detekt and what does running the `detekt` Gradle task do for a Kotlin project?
basics
~10 sdetekt is a static analysis tool for Kotlin. It scans your source code without running it and reports code smells, overly complex functions, and style problems so you can fix them.
What is ktlint, and what is the difference between the ktlintCheck and ktlintFormat Gradle tasks?
basics
~10 sktlint is a tool that checks and fixes Kotlin code style. ktlintCheck only reports problems and fails the build; ktlintFormat automatically rewrites your files to fix the fixable ones.
Explain the relationship between the apiDump and apiCheck tasks and the typical developer workflow when you intentionally change a public API.
basics
~20 sapiCheck compares your current public API to the saved file and fails if they differ. apiDump regenerates that saved file. When you intentionally change the API, you run apiDump and commit the updated file so the check passes again.
How does `detekt.yml` work, and what do `buildUponDefaultConfig` and `--build-upon-default-config` mean when configuring rules?
basics
~10 sdetekt.yml is a YAML file where you turn rules on or off and set their thresholds. With buildUponDefaultConfig, your file only overrides the defaults instead of replacing them entirely.
How do you enable Explicit API mode in a Kotlin Gradle build, and what is the difference between strict and warning levels?
basics
~10 sIn your Gradle build script's kotlin block, call explicitApi() for strict mode (build fails) or explicitApiWarning() for warnings only. Under the hood it passes a -Xexplicit-api compiler flag.