skip to content

How do @JvmName and @JvmMultifileClass change the file facade, and when would you use them?

level: seniorimportance: should knowfreq 35%

answer

  1. @file:JvmName renames the facade (above package)
  2. @file:JvmMultifileClass merges many files into one facade
  3. Both annotations on EVERY file, same JvmName
  4. Only affects Java view; Kotlin unaffected
  5. Renaming = binary-incompatible for Java

basics

~10 s

@JvmName renames the generated facade class so Java callers see a nicer name. @JvmMultifileClass lets several files share one facade class, so functions split across files appear under a single name to Java.

solid answer

~40 s

By default the facade class name is `<FileName>Kt`, which is often ugly for Java consumers. Putting a **file-level** annotation `@file:JvmName("StringUtils")` at the top of the file (before the `package` directive) renames the generated facade — Java then calls `StringUtils.foo()` instead of `MyKotlinFileKt.foo()`. If you want top-level functions spread across **multiple files** to appear under **one** Java class, you combine `@file:JvmName("...")` with `@file:JvmMultifileClass` on each contributing file; the compiler merges them into a shared facade. This is exactly how the standard library exposes e.g. `kotlin.collections.CollectionsKt`-style grouping cleanly. These annotations affect only the JVM-facing name; Kotlin call sites are unaffected. Misuse risk: renaming the facade is a binary-compatibility change for Java callers.

code

kotlin · 17 lines
kotlin
// File: TextA.kt
@file:JvmName("TextUtils")
@file:JvmMultifileClass
package com.example

fun trimAll(s: String) = s.trim()

// File: TextB.kt
@file:JvmName("TextUtils")
@file:JvmMultifileClass
package com.example

fun pad(s: String, n: Int) = s.padStart(n)

// Java sees a single class:
//   TextUtils.trimAll("  x ");
//   TextUtils.pad("x", 3);

go deeper

for a junior

Likely unaware these annotations exist; may only know the default Kt facade.

for a middle

Knows @file:JvmName renames the facade for Java but may miss the multifile merge requirements.

for a senior

Correctly applies both file-level annotations, explains the merge mechanics and the @file: target rule.

for a principal

Weighs Java API ergonomics vs binary-compatibility risk and designs facade naming as a stable public contract.

## The default and its problem A top-level function compiles into a facade named `<FileName>Kt`. For Java consumers, names like `StringExtensionsKt` are noisy, and you cannot split a logically-single API across multiple files without each file producing its own facade. ## `@JvmName` — rename the facade Apply it as a **file-level** annotation, placed **above the `package` directive**: ```kotlin @file:JvmName("StringUtils") package com.example fun shout(s: String) = s.uppercase() ``` Now the generated class is `com.example.StringUtils`, so Java writes `StringUtils.shout("hi")` instead of `StringUtilsKt.shout(...)`. The `@file:` **use-site target** is mandatory here — it tells the compiler the annotation applies to the whole file/facade, not to a single declaration. (Note: `@JvmName` on an individual `fun` renames *that method*, used to dodge JVM signature clashes; on a *file* it renames the *facade class*. Same annotation, two targets.) ## `@JvmMultifileClass` — merge facades If an API is large, you may want to keep Kotlin source in several files but present **one** Java class. Add **both** annotations to **each** file, using the **same** `@JvmName`: ```kotlin // File: ListsCore.kt @file:JvmName("Lists") @file:JvmMultifileClass package com.example fun first2(...) { } // File: ListsExtra.kt @file:JvmName("Lists") @file:JvmMultifileClass package com.example fun last2(...) { } ``` The compiler generates a single public `com.example.Lists` facade that delegates to per-file part classes. Java sees `Lists.first2(...)` and `Lists.last2(...)` as if from one class. The Kotlin standard library uses exactly this pattern (e.g. the `kotlin.collections` helpers). ## Rules and gotchas - Both annotations are **file-level** (`@file:`) and must sit above `package`. - For multifile merging, **every** participating file needs **both** annotations with the **identical** JvmName; otherwise you get a duplicate-class or split-facade error. - You **cannot** have a top-level declaration whose facade name collides with a real class of the same name. - Changing or removing these names is a **binary-incompatible** change for Java callers (Kotlin callers are unaffected because they never reference the facade). ## When to use - Library authors exposing a clean Java API surface. - Grouping a big helper API into readable source files without fragmenting the Java-visible class. - Pure-Kotlin internal code rarely needs either annotation.

  • Why must @JvmMultifileClass appear on every contributing file?
    Each file independently produces facade bytecode; the compiler only merges files that opt in with the same JvmName and the multifile annotation.
  • Does @file:JvmName affect how Kotlin code calls the function?
    No. Kotlin resolves by package and symbol, ignoring the facade name; only Java callers see the renamed class.

saying these in an interview costs you the question

  • Putting @JvmName on the function when the goal is to rename the facade
  • Forgetting @file: use-site target or placing it after package
  • Omitting @JvmMultifileClass on some files in the group
  • Claiming the rename affects Kotlin call sites
  • Ignoring that renaming breaks existing Java callers

context