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.
valmeans the variable can be assigned once.const valmeans 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 acompanion 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
valfor values that should not be reassigned. - Use
const valonly 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 referenceconst val= fixed compile-time literal
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
-
const val TAX_RATE = 0.2- Kotlin reads this as a compile-time constant.
- The value
0.2is fixed and known before execution.
-
val price = 100.0- When
main()runs,priceis created. - It cannot be reassigned later.
- When
-
val total = price + (price * TAX_RATE)- Kotlin uses
pricefrom runtime. - It uses
TAX_RATEas a constant value. - The expression becomes
100.0 + (100.0 * 0.2).
- Kotlin uses
-
println(total)- Prints
120.0.
- Prints
Key observation
priceis avalbecause it is created when the program runs.TAX_RATEis aconst valbecause 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.
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
valfor local variables and properties that should not change. - Use
const valfor 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:
valprotects 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
| Feature | val | const val |
|---|---|---|
| Reassignment allowed? | No | No |
| Known at compile time? | Not required | Required |
| Can use runtime function calls? | Yes | No |
| Allowed for local variables? | Yes | No |
| Allowed types | Any type | Primitive types and String |
| Can be used in annotations? | Usually no | Yes |
| Typical use | Read-only values | Fixed constants |
var vs val vs const val
| Keyword | Meaning | Best use |
|---|---|---|
var | Mutable variable | Value needs to change |
val | Read-only reference | Default for most values |
const val | Compile-time constant | Fixed 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
Cheat Sheet
Quick rules
val= assign onceconst val= assign once and known at compile time- every
const valis also effectively aval - not every
valcan beconst
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 acompanion 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 variableconst 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.
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 valvalues for fixed application settings. - Define at least two
valvalues that are computed when the program runs. - Print all values to show the difference in usage.
- Keep
const valdeclarations in valid locations. - Use only valid Kotlin syntax.
Keep learning
Related questions
Accessing Kotlin Extension Functions from Java
Learn how Kotlin extension functions are compiled and how to call them correctly from Java with clear examples and common pitfalls.
Add a Maven Repository URL in Gradle Kotlin DSL (build.gradle.kts)
Learn how to add Maven Central and a custom Maven repository URL in Gradle Kotlin DSL using build.gradle.kts syntax.
Allow HTTP and HTTPS in Android 9 Pie with Network Security Configuration
Learn how Android 9 Pie handles cleartext HTTP traffic and how to allow HTTP and HTTPS safely using network security config.