# When Is the Kotlin Init Block Executed Relative to the Primary Constructor?

> Understand when Kotlin init blocks execute relative to primary constructors. Learn about the execution order of parameters, properties, and init blocks in Kotlin.

- Repository: [JetBrains/kotlin](https://github.com/jetbrains/kotlin)
- Tags: internals
- Published: 2026-02-16

---

**The `init` block executes immediately after primary constructor parameters are evaluated, interleaved with property initializers in textual order, and before any constructor body statements.**

Understanding exactly when the kotlin init block executed is crucial for avoiding initialization bugs and side-effect ordering issues. According to the JetBrains/kotlin source code, the compiler treats `init` blocks as part of the primary constructor execution path, merging them with property initializers during the lowering phase. This article explains the precise execution order using actual compiler implementation details from the Kotlin repository.

## Kotlin Init Block Execution Order

The kotlin init block executed follows a strict three-phase sequence that is guaranteed by the language specification and enforced by the compiler's IR lowering passes.

### Step 1: Primary Constructor Parameter Evaluation

First, all arguments supplied to the primary constructor are evaluated and assigned to the constructor parameters. This happens before any class body code runs, ensuring that `init` blocks and property initializers can safely reference constructor parameters.

### Step 2: Property Initializers and Init Blocks in Textual Order

After parameters are ready, the compiler executes **all property initializers and `init` blocks in the exact textual order they appear in the class body**. This interleaving is a critical detail: an `init` block runs immediately after the property initializers that precede it in the source file, and before any that follow.

This merging logic is implemented in [`compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt), which combines anonymous initializers (the IR representation of `init` blocks) with field initializers into a single ordered list that is then injected into the constructor.

### Step 3: Primary Constructor Body

Finally, if the primary constructor declaration includes a body (statements between curly braces after the parameter list), those statements execute after all property initializers and `init` blocks have completed.

## Compiler Implementation Details

The precise timing of when the kotlin init block executed is enforced by several key components in the Kotlin compiler pipeline.

### JVM Backend: JvmInitializersLowering.kt

For JVM targets, the [`compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInitializersLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/ir/backend.jvm/lower/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInitializersLowering.kt) file handles the transformation. It merges field initializers and `init` blocks into the generated `<init>` method while preserving the textual order defined in the source code. This ensures that the bytecode reflects the exact interleaving required by the language specification.

### Common IR Lowering: InitializersLowering.kt

The platform-agnostic logic resides in [`compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/ir/backend.common/src/org/jetbrains/kotlin/backend/common/lower/InitializersLowering.kt). This pass runs before target-specific code generation and constructs the ordered sequence of initialization statements. By handling this at the IR level, the compiler guarantees consistent `init` block behavior across JVM, JavaScript, and Native targets.

### PSI Representation: KtAnonymousInitializer.kt

At the front-end level, `init` blocks are represented by [`compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtAnonymousInitializer.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/psi/psi-api/src/org/jetbrains/kotlin/psi/KtAnonymousInitializer.kt). This PSI (Program Structure Interface) element captures the block's content and position within the class body, providing the textual order information that later lowering passes rely on.

### Control Flow Graph: ControlFlowGraphBuilder.kt

The FIR (Front-end IR) analysis phase uses [`compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt`](https://github.com/JetBrains/kotlin/blob/main/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt) to model initialization order. It treats each `init` block as a distinct CFG node positioned between the class entry node and the constructor body, formally verifying that the block executes after parameter setup but before constructor completion.

## Code Examples Demonstrating Init Block Timing

### Example 1: Textual Ordering of Initializers

The following example demonstrates how the kotlin init block executed is interleaved with property initializers based on source position.

```kotlin
class Demo(val a: Int) {
    val x = a * 2          // property initializer (runs after `a` is ready)
    init {
        println("init 1, a=$a, x=$x")
    }
    val y = a + 10         // second property initializer
    init {
        println("init 2, y=$y")
    }
}

```

**Runtime output:**

```

init 1, a=5, x=10
init 2, y=15

```

*Explanation*:  
1. Argument `5` is evaluated for `a`.  
2. `x` initializer runs (`x = 5 * 2`).  
3. First `init` block runs.  
4. `y` initializer runs (`y = 5 + 10`).  
5. Second `init` block runs.

### Example 2: Secondary Constructor Delegation

When using secondary constructors, the `init` block runs during the delegated primary constructor call.

```kotlin
class Person(val name: String) {
    init { println("Primary init: $name") }

    constructor(name: String, age: Int) : this(name) {
        println("Secondary ctor body, age=$age")
    }
}

```

**Runtime when `Person("Bob", 30)` is created:**

```

Primary init: Bob
Secondary ctor body, age=30

```

The secondary constructor first delegates to the primary one via `: this(name)`, which triggers the `init` block *before* the secondary constructor's own body executes.

### Example 3: Custom Getters and Init Blocks

Properties with custom getters do not affect initialization timing because the getter executes only upon property access, not during construction.

```kotlin
class Counter(start: Int) {
    var count = start          // initializer runs after `start` is evaluated
    init { count++ }           // init block runs next
    val isPositive get() = count > 0   // getter evaluated only when accessed
}

```

Creating `Counter(0)` produces no output but leaves `count == 1` because the `init` block increments the already-initialized property. The `isPositive` getter remains dormant until explicitly called.

## Summary

- The kotlin init block executed **after** primary constructor parameters are evaluated but **before** the constructor body completes.
- Initialization follows **strict textual order**: property initializers and `init` blocks are interleaved exactly as they appear in the source file.
- The compiler enforces this order through **IR lowering passes** in [`InitializersLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/InitializersLowering.kt) (common) and [`JvmInitializersLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/JvmInitializersLowering.kt) (JVM), which merge initializers into the constructor bytecode.
- Secondary constructors trigger `init` blocks during delegation to the primary constructor, ensuring consistent initialization regardless of which constructor is invoked.

## Frequently Asked Questions

### Does the init block run before or after the primary constructor?

The `init` block runs **during** the primary constructor execution, specifically after parameter evaluation but before any explicit constructor body statements. It is not separate from the constructor; rather, it constitutes part of the constructor's initialization phase as implemented in [`InitializersLowering.kt`](https://github.com/JetBrains/kotlin/blob/main/InitializersLowering.kt).

### What happens if I have multiple init blocks in a Kotlin class?

Multiple `init` blocks execute **in the order they appear in the source code**, interleaved with property initializers. The compiler treats each block as a separate anonymous initializer node in the IR, then concatenates them with field initializers according to their textual position, ensuring deterministic, sequential execution.

### Is the init block executed when using a secondary constructor?

Yes. When a secondary constructor delegates to the primary constructor (via `: this(...)`), the primary constructor's initialization sequence—including all `init` blocks—runs before the secondary constructor's body executes. If the secondary constructor delegates to another secondary constructor, the chain eventually reaches the primary, triggering the `init` blocks at that point.

### Can I access all primary constructor parameters inside an init block?

Yes. Primary constructor parameters are **fully available** inside `init` blocks because parameter evaluation completes before the initialization sequence begins. You can read constructor parameters, use them to initialize other properties, and call methods on them, though the compiler will warn if you attempt to access properties that are declared *after* the `init` block in the source file before they are initialized.