Question
In Kotlin, what is the exact difference between var and val?
I read the Kotlin documentation about properties and fields, which says that a read-only property declaration:
- starts with
valinstead ofvar - does not allow a setter
However, the documentation also shows code like this:
fun copyAddress(address: Address): Address {
val result = Address() // there's no 'new' keyword in Kotlin
result.name = address.name // accessors are called
result.street = address.street
// ...
return result
}
This confused me because result is declared with val, but its properties are still being changed.
So:
- What is the exact difference between
varandvalin Kotlin? - Why does Kotlin need both?
- Why is it valid to modify
result.nameandresult.streetwhenresultitself is declared withval?
Short Answer
By the end of this page, you will understand that val means the reference cannot be reassigned, while var means it can. You will also see why a val object can still have mutable internal properties, how this differs from full immutability, and how Kotlin developers use val and var in real code.
Concept
In Kotlin, val and var describe whether a variable or property reference can be reassigned.
Core idea
val= read-only referencevar= mutable reference
That means:
val name = "Ava"
// name = "Liam" // not allowed
var city = "Paris"
city = "Rome" // allowed
What val really means
A val does not mean the object itself is deeply immutable.
It only means that the variable now always points to the same object.
If that object has mutable properties, those properties can still change.
For example:
class Address {
var name: String = ""
var street: String = ""
}
val result = Address()
result.name = "Sam" // allowed
result.street = "Main" // allowed
// result = Address() // not allowed
Here, result always refers to the same Address instance, but the inside of that instance can still be modified because name and street are declared as var.
Why this matters
This distinction is important in real programming because it separates two different ideas:
- Can I point this variable to a different object?
- Can the object itself change internally?
Kotlin lets you control both.
- Use
valwhen the reference should stay fixed. - Use
varwhen reassignment is part of the logic. - Use
valproperties inside a class when the object's state should not change after creation.
About the documentation example
The documentation is not saying that a val object can never be changed in any way.
It is saying that a val property itself has no setter.
So this is illegal:
val result = Address()
// result = anotherAddress
But this is legal if the Address class has mutable properties:
result.name = address.name
That line is not reassigning result. It is modifying a property on the object that result refers to.
Mental Model
Think of a variable as a label attached to a box.
valmeans the label must stay attached to the same box.varmeans you can move the label to a different box later.
Now think about the contents of the box.
Even if the label is fixed (val), the contents inside the box may still be changed.
Analogy
val box = Address()
This means:
- you must keep using the same box
- but you may still put different things inside it, if the box allows that
So:
box.name = "Alice"
changes the contents of the box.
But:
box = Address()
tries to replace the entire box, which val does not allow.
Easy rule to remember
valprotects the referencevarallows changing the reference- object mutability depends on the object's own properties, not just on
valorvar
Syntax and Examples
Basic syntax
val x = 10
var y = 20
xcannot be reassignedycan be reassigned
Example 1: Primitive-like values
val age = 25
// age = 26 // error
var score = 100
score = 120 // okay
Example 2: Object references
class User {
var name: String = ""
}
val user = User()
user.name = "Maya" // okay
// user = User() // error
Explanation
useris aval, so it must keep pointing to the sameUserobject.nameis avarproperty insideUser, so it can change.
Example 3: Truly read-only object state
data class Person(val name: String, val age: Int)
val person = Person("Nina", 30)
// person.name = "Eva" // error
// person = Person("Eva", 31) // error
Here both levels are read-only:
personis avalPersonproperties are alsoval
So neither the reference nor the object's fields can be changed.
Example 4: var property vs val property in a class
class Counter {
var count: Int = 0
val label: String = "Clicks"
}
counthas a getter and setterlabelhas only a getter
That is what the documentation means when it says a val property does not allow a setter.
Step by Step Execution
Consider this code:
class Address {
var name: String = ""
var street: String = ""
}
fun copyAddress(address: Address): Address {
val result = Address()
result.name = address.name
result.street = address.street
return result
}
Step-by-step
1. A new Address object is created
val result = Address()
- Kotlin creates a new
Addressinstance. resultstores a reference to that object.- Because
resultisval, that reference cannot later point to anotherAddress.
2. The name property is copied
result.name = address.name
- Kotlin reads
address.name. - Kotlin calls the setter for
result.name. - This changes the
nameproperty inside the object referred to byresult. resultitself is not reassigned.
3. The street property is copied
result.street = address.street
- Same idea as above.
- The object changes internally.
- The reference stored in
resultstays the same.
4. The object is returned
return result
- The same
Addressobject is returned.
What would be illegal?
fun badCopy(address: Address): Address {
val result = Address()
// result = address // error
return result
}
This is illegal because it tries to reassign the result variable itself.
Short trace
| Line | What changes? |
|---|---|
val result = Address() | result starts pointing to one new object |
result.name = ... | object state changes |
result.street = ... | object state changes |
return result | same object is returned |
Real World Use Cases
1. Safer local variables
Most local variables do not need reassignment.
val response = api.getUser()
val parsed = parseUser(response)
Using val makes code easier to reason about because you know those names will not suddenly point somewhere else later.
2. Mutable app state where needed
Sometimes reassignment is required.
var currentPage = 1
currentPage += 1
This is a good use of var because the value is expected to change.
3. Working with mutable objects
You often keep one reference fixed while changing its contents.
val cart = mutableListOf("Book")
cart.add("Pen")
cart.add("Notebook")
cart is still the same list reference, but the list contents change.
4. Domain models with immutable fields
For data you do not want changed accidentally:
data class Order(val id: String, val total: Double)
This helps avoid bugs in business logic.
5. Configuration values
val baseUrl = "https://api.example.com"
Configuration constants are usually val because they should not be reassigned during execution.
Real Codebase Usage
In real Kotlin projects, developers usually prefer val by default and switch to var only when mutation is necessary.
Common patterns
Prefer val for local variables
val user = repository.findById(id)
val dto = user.toDto()
return dto
This reduces accidental reassignment.
Use var for changing state
var retries = 0
while (retries < 3) {
retries++
}
Use immutable data models when possible
data class User(val id: Int, val name: String)
When data must change, Kotlin code often creates a new object instead of mutating the old one.
data class User(val id: Int, val name: String)
val user = User(1, "Ana")
val updatedUser = user.copy(name = "Anna")
Guard clauses and validation
Developers often store validated values in val variables after checks.
fun register(name: String?) {
require(!name.isNullOrBlank())
val cleanName = name.trim()
println(cleanName)
}
Mutable collections behind read-only references
val items = mutableListOf<String>()
items.add("A")
This is common when the collection contents should change, but the variable should keep referring to the same collection.
Practical rule used by teams
- Start with
val - Change to
varonly if reassignment is actually needed
Common Mistakes
1. Thinking val means fully immutable
This is the most common mistake.
val numbers = mutableListOf(1, 2, 3)
numbers.add(4) // allowed
numbers is read-only as a reference, but the list object is mutable.
How to avoid it
Check both:
- is the reference
valorvar? - is the object itself mutable or immutable?
2. Confusing property mutation with variable reassignment
Broken mental model:
val user = User()
user.name = "Lee" // some beginners expect error here
This is valid if name is a mutable property.
How to avoid it
Remember: user.name = ... changes the object, not the user reference.
3. Using var everywhere
var name = "Sara"
var age = 20
If values never change, var adds unnecessary mutability.
Better
val name = "Sara"
val age = 20
4. Expecting a val class property to have a setter
Broken code:
class Product {
val id: Int = 1
}
fun main() {
val product = Product()
// product.id = 2 // error
}
A val property only has a getter.
5. Assuming val and var are about memory or performance
They are mainly about correctness and mutability rules, not about manually controlling memory.
6. Mixing up read-only interfaces and immutable objects
val names: List<String> = mutableListOf("A", "B")
This gives a read-only view through List, but the underlying object may still be mutable elsewhere.
How to avoid it
Do not assume read-only access always means the object can never change.
Comparisons
val vs var
| Feature | val | var |
|---|---|---|
| Can be reassigned? | No | Yes |
| Has getter? | Yes | Yes |
| Has setter? | No | Yes |
| Best default choice? | Yes | Only when needed |
| Guarantees object immutability? | No | No |
Reference mutability vs object mutability
| Situation | Allowed? | Why? |
|---|---|---|
Reassign a val variable | No | reference is fixed |
Change a mutable property inside a val object | Yes | object state can change |
Reassign a var variable | Yes | reference is mutable |
Change a val property inside a class | No | property has no setter |
Kotlin vs Java intuition
| Kotlin | Rough Java idea |
|---|---|
val local variable | similar to final reference |
var local variable | normal reassignable variable |
The Java comparison is helpful, but not perfect. In Kotlin, val is the language's standard way to express a read-only reference.
Cheat Sheet
Quick rules
val= cannot reassign the variable/propertyvar= can reassign the variable/propertyvaldoes not automatically make the object immutable- A
valproperty has a getter only - A
varproperty has a getter and setter
Basic syntax
val a = 10
var b = 20
Object example
val user = User()
user.name = "Kai" // okay if name is var
// user = User() // error
Class property example
class Example {
val x = 1
var y = 2
}
xcannot be assigned after initializationycan be changed later
Best practice
- Use
valby default - Use
varonly when reassignment is required
Important edge case
val list = mutableListOf(1, 2)
list.add(3) // allowed
val protects the reference, not the contents.
FAQ
Why can I change properties of a val object in Kotlin?
Because val only prevents reassigning the reference. If the object has mutable (var) properties, those properties can still be changed.
Is val the same as immutable in Kotlin?
No. val means read-only reference, not deep immutability.
Is val similar to final in Java?
Yes, for references it is very similar. A val reference cannot be pointed to another object after assignment.
Should I always use val instead of var?
Use val by default. Change to var only when your logic needs reassignment.
Can a class have both val and var properties?
Yes. This is very common. Some fields stay fixed, while others are allowed to change.
Why does Kotlin provide both val and var?
Because programs need both stable references and mutable state. The two keywords make that choice explicit and readable.
Mini Project
Description
Build a small Kotlin program that demonstrates the difference between changing a reference and changing the contents of an object. This helps make the val vs var distinction concrete using a simple profile model.
Goal
Create a program that shows: a val reference can keep the same object while its mutable properties change, and a var reference can be reassigned to a different object.
Requirements
- Create a class with at least one
varproperty and onevalproperty. - Declare one object using
valand modify only its mutable property. - Declare another object using
varand reassign it to a new instance. - Print the results so the difference is visible.
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.