skip to content

What is the Kotlin/JS IR target, and how do you enable it in a Gradle build with browser() and nodejs() environments?

level: juniorimportance: must knowfreq 55%

answer

  1. IR = Intermediate Representation backend
  2. Only backend since Kotlin 1.8 (legacy removed)
  3. js(IR) { browser() / nodejs() }
  4. binaries.executable() = runnable output
  5. browser=DOM+webpack, nodejs=Node runtime

basics

~10 s

Kotlin/JS lets you compile Kotlin code into JavaScript. The IR target is the modern compiler backend. In Gradle you add js(IR) and pick browser() or nodejs() depending on where the code runs.

solid answer

~40 s

Kotlin/JS compiles Kotlin to JavaScript so the same language runs in browsers or Node. The IR (Intermediate Representation) backend is the modern, only-supported compiler since Kotlin 1.8; the old 'legacy' backend was removed. You declare the target in the Kotlin Gradle DSL with kotlin { js(IR) { ... } }, then choose an environment: browser() configures a webpack-based dev server and bundling for the DOM, while nodejs() targets the Node.js runtime. You can declare both. binaries.executable() tells the compiler to emit a runnable artifact rather than just a library. The IR backend enables features the legacy one couldn't: efficient Dead Code Elimination, ES-module output, and TypeScript declaration generation via generateTypeScriptDefinitions().

code

kotlin · 7 lines
kotlin
kotlin {
    js(IR) {
        browser()
        nodejs()
        binaries.executable()
    }
}

go deeper

for a junior

Knows Kotlin/JS compiles Kotlin to JavaScript and can name js(IR) with browser/nodejs.

for a middle

Explains IR is the only backend since 1.8 and the role of binaries.executable() and environment choice.

for a senior

Connects the IR backend to downstream capabilities (DCE, ES modules, .d.ts) and configures both environments deliberately.

for a principal

Reasons about migration from legacy, build-tooling implications, and when a klib-only vs executable output is the right module boundary.

## What Kotlin/JS is Kotlin/JS is a compilation target that translates Kotlin source into JavaScript, letting you share Kotlin logic with web frontends, Node services, or npm packages. It is one of several targets in a Kotlin Multiplatform (KMP) project alongside JVM, Native, and Wasm. ## What 'IR' means IR stands for **Intermediate Representation** — a compiler-internal tree the frontend produces before generating output. Kotlin originally had a 'legacy' JS backend that translated straight to JS. The **IR backend** instead lowers code through the same shared IR pipeline used by Kotlin/Native, which unlocks better optimization. Since **Kotlin 1.8** the IR backend is the only one; `js(LEGACY)` and the mixed `js(BOTH)` mode were removed. So today `js(IR)` and plain `js` are equivalent. ## Enabling it in Gradle You configure targets inside the `kotlin { }` block of the Kotlin Multiplatform Gradle plugin. ```kotlin kotlin { js(IR) { browser { // DOM / webpack environment commonWebpackConfig { cssSupport { enabled.set(true) } } } nodejs() // Node.js environment (can coexist) binaries.executable() // emit a runnable bundle, not just a klib } } ``` ## browser() vs nodejs() - **browser()** wires in a webpack-backed dev server (`browserDevelopmentRun`), production/development bundling, and assumes a DOM. Use it for web apps. - **nodejs()** targets the Node runtime, gives you `nodeRun`/test tasks, and assumes Node globals (no DOM). Use it for CLIs, scripts, or server code. - You may declare both; each gets its own runtime-specific tasks. ## binaries.executable() Without it, the target builds a **klib** (Kotlin library) only. With it, the compiler emits an actual JavaScript entry artifact you can run or ship. ## Why it matters The IR backend is the foundation for the other features on this topic: tree-shaking via Dead Code Elimination, ES-module output, and TypeScript `.d.ts` generation.

  • If you write plain js {} instead of js(IR) {}, which backend do you get today?
    The IR backend. Since Kotlin 1.8 it's the only one, so js and js(IR) are equivalent; the explicit IR argument is now redundant but still accepted.
  • What is produced if you omit binaries.executable()?
    Only a klib library artifact, not a runnable JS bundle. You'd use that when the module is consumed by another Kotlin target rather than run directly.

The IR backend is like a shared assembly line: JS, Native, and Wasm all feed the same optimizing machinery instead of each having a bespoke conveyor belt.

saying these in an interview costs you the question

  • Thinking the legacy backend is still selectable or default
  • Believing browser() and nodejs() are mutually exclusive
  • Confusing IR (compiler representation) with a JS framework
  • Forgetting binaries.executable() and wondering why nothing runs
  • Claiming Kotlin/JS produces WebAssembly (that's the Wasm target)

context