Question

Kotlin const vs val: What’s the Difference?

kotlinconstants

Question

In Kotlin, what is the difference between const and val?

I recently read about the const keyword and got confused. Both const and val seem to be used for immutable values, so it is not obvious what practical difference exists between them. Am I missing an important distinction?

For example:

val name = "Kotlin"
const val APP_NAME = "MyApp"

When should each one be used, and what rules apply to const?

Short Answer

By the end of this page, you will understand that val means a read-only reference, while const val means a compile-time constant in Kotlin. You will learn where const is allowed, what types it supports, why it is more restrictive than val, and how developers typically use each one in real Kotlin codebases.

Concept

val and const val are related, but they are not the same thing.

  • val means the variable can be assigned once.
  • const val means the value is not only assigned once, but is also known at compile time.

val: read-only reference

A val creates a read-only reference. Once a value is assigned, you cannot reassign that variable.

val username = "alice"
// username = "bob" // Error

However, the value assigned to a val does not have to be known at compile time.

val currentTime = System.currentTimeMillis()

This is valid because currentTime is assigned only once, even though Kotlin can only get the value when the program runs.

const val: compile-time constant

A const val is a special kind of val.

Its value must be:

  • known at compile time
  • a primitive or String
  • declared at the top level, in an object, or in a companion object
const val MAX_USERS = 100
const val API_VERSION = "v1"

Kotlin can replace these values directly in places that require constants.

Why this matters

This distinction matters because some language features and annotations require a true constant expression.

For example:

annotation class Info(val message: String)

const val MESSAGE = "Hello"
val dynamicMessage = "Hi"

@Info(MESSAGE)      // Valid
// @Info(dynamicMessage) // Not valid
class Example

Even though dynamicMessage is immutable, it is still just a val, not a compile-time constant.

Important idea

A useful rule is:

  • Use val for values that should not be reassigned.
  • Use const val only for fixed values known before the program runs.

Mental Model

Think of val as a label on a box that cannot be moved to another box.

  • You attach the label once.
  • After that, the label must always point to the same thing.
  • But the thing inside may have been created at runtime.

Think of const val as a value printed in the instruction manual before the program even starts.

  • The value is fixed ahead of time.
  • The compiler already knows it.
  • It can copy that value directly wherever needed.

So:

  • val = fixed reference
  • const val = fixed compile-time literal
Take Quiz

Syntax and Examples

Basic syntax

val siteName = "Example"
const val APP_NAME = "MyApplication"

Example 1: regular val

val timestamp = System.currentTimeMillis()
println(timestamp)

This works because timestamp is assigned once. Its value is decided when the program runs.

Example 2: const val

const val DEFAULT_PORT = 8080
const val BASE_URL = "https://api.example.com"

These work because the values are compile-time constants.

Example 3: invalid const val

const val createdAt = System.currentTimeMillis() // Error

This fails because function calls are evaluated at runtime, not compile time.

Where const can be declared

Top-level

const val APP_VERSION = "1.0.0"

Inside an object

object Config {
    const val TIMEOUT = 5000
}

Inside a companion object

class ApiClient {
    companion object {
        const val BASE_PATH = "/api"
    }
}

Example explanation

If you need a fixed app version, API path, or default limit, const val is a good fit.

If the value depends on computation, user input, environment data, or function calls, use val.

Step by Step Execution

Consider this code:

const val TAX_RATE = 0.2

fun main() {
    val price = 100.0
    val total = price + (price * TAX_RATE)
    println(total)
}

Step by step

  1. const val TAX_RATE = 0.2

    • Kotlin reads this as a compile-time constant.
    • The value 0.2 is fixed and known before execution.
  2. val price = 100.0

    • When main() runs, price is created.
    • It cannot be reassigned later.
  3. val total = price + (price * TAX_RATE)

    • Kotlin uses price from runtime.
    • It uses TAX_RATE as a constant value.
    • The expression becomes 100.0 + (100.0 * 0.2).
  4. println(total)

    • Prints 120.0.

Key observation

  • price is a val because it is created when the program runs.
  • TAX_RATE is a const val because it is a fixed literal known in advance.

Real World Use Cases

When to use val

Use val for most read-only values in normal application code:

  • results from a database query
  • user input after validation
  • API response data
  • generated timestamps
  • parsed configuration values

Example:

val userId = request.getParameter("id")
val createdAt = System.currentTimeMillis()

When to use const val

Use const val for fixed values that never change and are known ahead of time:

  • API endpoint paths
  • intent keys
  • database column names
  • request timeout defaults
  • error codes
  • annotation arguments

Example:

const val EXTRA_USER_ID = "extra_user_id"
const val RETRY_LIMIT = 3
const val TABLE_NAME = "users"

Android example

object Keys {
    const val USER_ID = "user_id"
    const val SESSION_TOKEN = "session_token"
}

These values are ideal constants because they are fixed strings used across the app.

Take Quiz

Real Codebase Usage

In real Kotlin projects, developers usually prefer val by default and reserve const val for true constants.

Common patterns

Configuration constants

object Defaults {
    const val PAGE_SIZE = 20
    const val CACHE_DURATION_MINUTES = 60
}

Keys and identifiers

object JsonFields {
    const val NAME = "name"
    const val EMAIL = "email"
}

Companion object constants

class Logger {
    companion object {
        const val TAG = "Logger"
    }
}

Guard clauses with val

fun printName(name: String?) {
    val safeName = name ?: return
    println(safeName)
}

Here safeName is runtime data, so val is correct.

Validation and transformations

val trimmedEmail = input.trim()
val isValid = trimmedEmail.contains("@")

These are immutable values, but not compile-time constants, so they should be val.

Practical rule in codebases

  • Default to val for local variables and properties that should not change.
  • Use const val for shared fixed literals that represent permanent constants.

Common Mistakes

1. Thinking val means deeply immutable

val prevents reassignment of the reference, but the object itself may still be mutable.

val numbers = mutableListOf(1, 2, 3)
numbers.add(4) // Valid
// numbers = mutableListOf(5, 6) // Error

Avoid confusion by remembering:

  • val protects the variable reference
  • it does not automatically make the object immutable

2. Using const with runtime expressions

Broken example:

const val NOW = System.currentTimeMillis()

Why it fails:

  • System.currentTimeMillis() is only known at runtime.

Use this instead:

val now = System.currentTimeMillis()

3. Declaring const in the wrong place

Broken example:

fun main() {
    const val APP_NAME = "Demo" // Error
}

const val cannot be local inside a function.

Use this instead:

const val APP_NAME = "Demo"

fun main() {
    println(APP_NAME)
}

4. Using unsupported types with const

Broken example:

const val ROLES = listOf("admin", "user")

This fails because const only supports primitive types and String.

Use this instead:

val roles = listOf("admin", "user")

5. Using const when val is simpler

Some beginners overuse const because it sounds more strict. In Kotlin, val is the normal choice for immutability.

Use const val only when the value is truly a compile-time constant.

Comparisons

Featurevalconst val
Reassignment allowed?NoNo
Known at compile time?Not requiredRequired
Can use runtime function calls?YesNo
Allowed for local variables?YesNo
Allowed typesAny typePrimitive types and String
Can be used in annotations?Usually noYes
Typical useRead-only valuesFixed constants

var vs val vs const val

KeywordMeaningBest use
varMutable variableValue needs to change
valRead-only referenceDefault for most values
const valCompile-time constantFixed literals shared across code

Simple takeaway

  • If the value changes: use var
  • If the value should not change: use val
  • If the value is a fixed compile-time literal: use const val
Take Quiz

Cheat Sheet

Quick rules

  • val = assign once
  • const val = assign once and known at compile time
  • every const val is also effectively a val
  • not every val can be const

Use val when

val now = System.currentTimeMillis()
val user = getUser()
val total = price * quantity

Use const val when

const val APP_NAME = "Demo"
const val MAX_RETRIES = 3
const val API_PATH = "/users"

const val rules

  • must be known at compile time
  • must be primitive or String
  • must be top-level, in an object, or in a companion object
  • cannot be inside a function
  • cannot call functions to compute the value

Common invalid examples

const val NOW = System.currentTimeMillis()
const val ITEMS = listOf(1, 2, 3)

Memory aid

  • val = read-only variable
  • const val = true constant

FAQ

Is const the same as val in Kotlin?

No. const val is a compile-time constant, while val is only a read-only reference.

Can I use const inside a function?

No. const val cannot be declared as a local variable inside a function.

Can a val be calculated at runtime?

Yes. A val can store the result of a function call or any runtime expression.

Why would I use const val instead of val?

Use const val when the value is fixed, known at compile time, and needs to behave like a real constant, such as in annotation arguments or shared constant keys.

Can const val hold a list or object?

No. const val only supports primitive types and String.

Is val always immutable?

The reference is immutable, but the object it points to may still be mutable.

Should I use const val everywhere for safety?

No. In Kotlin, val is the standard choice. Use const val only when the value qualifies as a compile-time constant.

Take Quiz

Mini Project

Description

Build a small Kotlin constants file for an app configuration module. This project demonstrates when to use const val for fixed application constants and when to use regular val for values computed at runtime.

Goal

Create a simple program that stores fixed app settings with const val and calculates runtime values with val.

Requirements

  • Define at least two const val values for fixed application settings.
  • Define at least two val values that are computed when the program runs.
  • Print all values to show the difference in usage.
  • Keep const val declarations in valid locations.
  • Use only valid Kotlin syntax.
Take Quiz

Keep learning

Related questions

View more