Kotlin const vs val: what's the difference and which to choose?

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Kotlin const vs val: what's the difference and which to choose?

\n\n

You're writing code in Kotlin and suddenly wonder: "What's the actual difference between const and val? Both seem immutable, right?" Great question! This point confuses even experienced developers transitioning from Java or other languages. It's no surprise that on Stack Overflow the topic "What is the difference between 'const' and 'val'?" gets thousands of views. Today we'll settle this once and for all, break down the theory, and back it all up with live code examples.

\n\n

Ready? Let's go!

\n\n

Quick primer: what is val?

\n\n

Let's start with the simplest. val (from value) is an immutable reference. You can assign a value to it once and never change it again. Sounds familiar? Yes, it's analogous to final in Java or readonly in C#.

\n\n
val name: String = "Alice"\nname = "Bob" // Compilation error! Val cannot be reassigned
\n\n

But there's an important nuance: val guarantees that the reference won't change, but it does not guarantee the immutability of the object itself. If you use val with a mutable list (MutableList), you can still add and remove elements.

\n\n
val numbers = mutableListOf(1, 2, 3)\nnumbers.add(4) // Works!\n// numbers = mutableListOf(5, 6) // Error! Cannot reassign the reference
\n\n

val can be initialized either at declaration or later in the code (e.g., in a constructor or init block). Its value is computed at runtime.

\n\n

What about const? The strict guardian of compile time

\n\n

const is the stricter sibling of val. It is also immutable, but with a superpower: the value must be known at compile time. In other words, it's a true constant that the compiler can inline directly into the code.

\n\n

const has strict rules:

\n
    \n
  • Can only be declared at the file level (outside a class) or inside an object / companion object.
  • \n
  • Must be of a primitive type or String.
  • \n
  • Cannot be the result of a function call or computation — only a literal or another constant.
  • \n
\n\n
// Correct\nconst val PI = 3.14159\nconst val APP_NAME = "MyApp"\n\n// Incorrect\nconst val currentTime = System.currentTimeMillis() // Error! Value not known at compile time\nconst val userName = getName() // Error! Function call is not allowed
\n\n

Key differences: const vs val in a table

\n\n

For clarity, here's a comparison table:

\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Criterionconst valval
Initialization timeAt compile timeAt runtime
Where it can be declaredTop-level, object, companion objectAnywhere (inside a class, function, constructor)
Data typesOnly primitives and StringAny types (including objects, lists)
PerformanceMaximum (inlining)Standard
Usage in annotationsYesNo
\n\n

Practical example: annotations and performance

\n\n

One of the most

Blogs

Book Recommendations