skip to content

Explicit API Mode

Explicit API mode forces library authors to state visibility and return types on public declarations, catching things you never meant to expose. It matters far more for a published library than for an application.

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

questions

5

How do you enable Explicit API mode in a Kotlin Gradle build, and what is the difference between strict and warning levels?

level: middleimportance: must knowfreq 40%

answer

  1. explicitApi() = strict (errors), explicitApiWarning() = warning
  2. explicitApi = ExplicitApiMode.Strict/Warning/Disabled
  3. Sugar over -Xexplicit-api=...
  4. Start warning, migrate, then flip strict
  5. Scope to library/main, skip tests

basics

~10 s

In 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.

solid answer

~40 s

In the Kotlin Gradle DSL, the kotlin { } extension exposes explicitApi() and explicitApiWarning(). explicitApi() sets strict mode, which surfaces violations as compilation errors and fails the build; explicitApiWarning() reports the same issues as warnings without failing. Both are sugar over the compiler argument -Xexplicit-api=strict / -Xexplicit-api=warning, which you can also pass directly via freeCompilerArgs (or the older kotlinOptions). You can also set the explicitApiMode property to ExplicitApiMode.Strict, Warning, or Disabled. A common pattern is enabling it for published library modules but not for test or sample source sets, since tests don't need a curated public surface — Gradle applies it to the main compilation but you can scope it as needed.

code

kotlin · 12 lines
kotlin
kotlin {
    explicitApi() // strict
}

// equivalent low-level form:
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
kotlin { explicitApi = ExplicitApiMode.Strict }

// raw flag:
tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach {
    compilerOptions.freeCompilerArgs.add("-Xexplicit-api=strict")
}

go deeper

for a junior

Knows you add explicitApi() in the kotlin block.

for a middle

Distinguishes explicitApi() strict from explicitApiWarning(), and names the ExplicitApiMode enum / -Xexplicit-api flag.

for a senior

Describes a warning-to-strict migration and CI enforcement, and scoping to main vs test.

for a principal

Standardizes the policy across many library modules (convention plugin), balances strictness with build noise, and ties it into release governance.

## Enabling it via the Kotlin Gradle DSL The `kotlin { }` extension provides two convenience functions: ```kotlin // build.gradle.kts kotlin { explicitApi() // strict — violations are ERRORS, build fails // explicitApiWarning() // warnings only — build still succeeds } ``` These are shorthand for setting the **`explicitApiMode`** property: ```kotlin import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode kotlin { explicitApi = ExplicitApiMode.Strict // or .Warning or .Disabled } ``` ## The underlying compiler flag Both helpers ultimately add a compiler argument: - `-Xexplicit-api=strict` - `-Xexplicit-api=warning` - `-Xexplicit-api=disable` You can pass it manually if you prefer or need finer control: ```kotlin tasks.withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>().configureEach { compilerOptions.freeCompilerArgs.add("-Xexplicit-api=strict") } ``` ## Strict vs warning | Mode | Reported as | Build outcome | |------|-------------|---------------| | **strict** (`explicitApi()`) | compile **errors** | **fails** on any violation | | **warning** (`explicitApiWarning()`) | compile **warnings** | succeeds | | **disable** | nothing | succeeds | The `-X` prefix means these are still technically experimental/advanced compiler flags, but the Gradle DSL functions are the stable, recommended entry point. ## Scoping The Kotlin Gradle plugin applies the mode to the module's compilations. **Test source sets do not need a curated public API**, so a typical approach is to enable it on library/main modules only — application and test modules usually leave it off. A migration strategy is to start with `explicitApiWarning()`, clean up the reports incrementally, then flip to `explicitApi()` and wire it into CI so regressions fail the build.

  • How would you migrate a large existing library to strict mode without breaking CI immediately?
    Turn on explicitApiWarning() first, fix the reported declarations gradually, then switch to explicitApi() and let CI enforce it.
  • Should you enable it on test source sets?
    Usually not — tests have no curated public surface, so the curation noise adds no value there.

saying these in an interview costs you the question

  • Saying explicitApi() only warns instead of failing the build
  • Not knowing it maps to -Xexplicit-api
  • Claiming there's no warning-only level
  • Thinking you must edit the compiler invocation manually — the DSL function exists
  • Confusing it with enabling a separate plugin

context

open as a page

What is Kotlin's Explicit API mode, and what two things does it require library authors to do?

level: juniorimportance: should knowfreq 35%

basics

~10 s

It's a compiler mode for libraries. It forces you to write the visibility keyword (like public) and the return type on everything your library exposes, so nothing leaks out by accident.

open as a page

Under Explicit API strict mode, which declarations get flagged and which are exempt? Give concrete examples.

level: middleimportance: should knowfreq 30%

basics

~10 s

It flags things visible outside your module — public and protected members that don't say their visibility, and public functions/properties with no written return type. Private, internal, local code, and overrides are left alone.

open as a page

Explicit API mode and the Binary Compatibility Validator both guard a library's API. How do they differ, and why might you use both?

level: seniorimportance: should knowfreq 22%

basics

~20 s

Explicit API mode works while you type — it forces you to declare what's public and its type. Binary Compatibility Validator works at review time — it diffs a saved snapshot of your public API so accidental breaking changes show up. They cover different moments.

open as a page

You lead a multi-module Kotlin library. Design an adoption strategy for Explicit API mode that doesn't paralyze the team, and explain the trade-offs.

level: seniorimportance: nice to knowfreq 14%

basics

~20 s

Turn it on as warnings first so nothing breaks, clean up module by module, then switch to strict and let CI enforce it. Apply it only to published modules, not apps or tests, and standardize the setting in one shared build convention.

open as a page