Kotlin

Why val is better than var

·17 min read

When I first encountered val and var in Kotlin, they seemed trivial. Three letters each. Just two keywords for declaring variables, right?

Here's the thing though: behind those three letters lies one of the most powerful ideas in software engineering. Immutability — the principle that once a value is set, it stays set.

Think of it this way: val is a locked safe. You put something inside, close the door, and that's it. Nobody can change what's in there. var is an open mailbox — anyone walking by can swap the contents.

Kotlin
// ❌ Before: var — anyone can reassign
var name = "Pavel"
name = "Alex"    // Sure, why not?
name = "Sandra"  // Changed again...
name = null       // Wait, now it's null?!

// ✅ After: val — set once, done
val name = "Pavel"
name = "Alex"  // Compilation error! The compiler stops you.
Rendering diagram...

When you see val in code, you know something powerful: this value will not change. No need to scroll down 50 lines to check if someone reassigned it. No need to trace through three functions to see if it got mutated. The value is what it says it is.

With var, every time you read the variable, you have to wonder: "Is this still the same value I saw 10 lines ago?" That cognitive load adds up. Fast.

This is predictability — and it's not just a nice-to-have. It's the difference between code you can reason about in your head and code that requires a debugger to understand.

Here's where val goes from "nice convention" to "real superpower": thread safety.

Imagine two threads running at the same time, both reading a variable. If it's a val, both threads see the same value. Always. No locks needed, no synchronization, no race conditions. The data is immutable, so there's nothing to fight over.

But if it's a var? Thread A reads the value. Thread B changes it. Thread A uses the old value. Boom — a bug that only appears under load, at 3 AM, in production. These are the worst bugs to find.

The diagram below shows exactly why.

Rendering diagram...

Real talk: In my Kotlin codebase, about 95% of variables are val. When I see var, I treat it as a red flag — something that needs justification. Why does this need to change? Could I restructure the code to avoid it?

This single habit — defaulting to val — eliminates entire categories of bugs.

So when should you use var? Honestly, not often. But there are legitimate cases:

  • Loop counters (for (i in 0..n) — though Kotlin's for often avoids this)
  • State machines that must mutate
  • Performance-critical code where object allocation matters
  • Building something in stages where you can't use a constructor

The key is intentionality. Don't use var out of habit. Use it because you understand why this specific value needs to change. And when you do, add a comment explaining why.

Rendering diagram...
Start with val. Let the compiler tell you when you actually need var.
— Rule of thumb
Pavel Ponomarev

About Me

I'm Pavel — a software engineer with 10+ years of experience building robust systems in Java, Kotlin, Python, Go, and TypeScript. Currently focused on AI agents, LLM workflows, and writing about what I learn along the way.

Stay in the loop

Get notified when I publish new articles about software craftsmanship, AI agents, and engineering empathy.

© 2026 Result Crafter Blog. Building software that works.