Extension property in Kotlin — what it is, syntax and usage

Author: IT Sectr Published: 2026-06-21 Reading time: 8 min

extension property — a Kotlin mechanism that allows adding new properties to existing classes without inheritance and without modifying the source code. Unlike extension functions, extension properties cannot store state — they are declared only with a getter and, optionally, a setter, since they do not have a backing field. According to Kotlin Documentation, 2025, extension properties compile into static getter and setter methods with the receiver as the first parameter.

Key Takeaways

  • Extension property — a property with a receiver type, accessible via Kotlin property syntax
  • No backing field — an extension property cannot store state, only compute
  • Getter is mandatory, setter is optional — declared like regular extension functions
  • Nullable types are supported: the receiver can be nullable with an internal check
  • Mutable extension property — only when declared as var with a getter and setter

What is an extension property in Kotlin?

An extension property is a syntactic construct in Kotlin that adds a property to an existing type without changing its declaration. The property is declared with a receiver type and must contain a getter. The key difference from regular properties is the absence of a backing field: an extension property cannot store data, only compute it based on the receiver object.

According to the Kotlin Foundation Survey (2024), extension properties are less popular than extension functions — about 45% of developers use them regularly. This is due to the limitation of having no state, which narrows the scope of application. Nevertheless, for computed properties that are logically tied to a type, extension properties are the most concise option.

Extension properties compile into a pair of static getter and setter methods. At the bytecode level, there is no difference between calling an extension property and calling an extension function — both become static methods with a receiver parameter. According to JetBrains (Kotlin Docs, 2025), there is no overhead at all.

Use extension properties for short computed values that should look like properties rather than method calls — this improves code readability and adheres to the Uniform Access Principle.

Extension property syntax: val and var

To declare an extension property, use a syntax similar to a regular property, but with the receiver type prefix. val declares a read-only extension property with a mandatory getter, var declares a mutable one with a getter and an optional setter.

kotlin
// Read-only extension property
val String.isEmail: Boolean
    get() = this.contains("@") && this.contains(".")

// Call
val valid = "test@test.com".isEmail

Note: an extension property is called without parentheses — str.isEmail, not str.isEmail(). This is the key difference between an extension property and an extension function: a property looks like a field, although it is actually computed through a getter.

Generic extension property

Extension properties can be generic — the receiver can use generic type parameters. This allows creating universal properties that work with any collection type.

kotlin
val List<T>.secondOrNull: T?
    get() = if (size >= 2) this[1] else null

val items = listOf("a", "b", "c")
val second = items.secondOrNull // "b"

The secondOrNull property works for any type T, returning the second element of the list or null if there are fewer than two elements. This is a typical example where an extension property is more appropriate than a function — accessing it looks like reading a field.

Why an extension property cannot store state

An extension property cannot have a backing field because it is not added to the class metadata — it exists only as a pair of static getter/setter functions. Backing field (the field keyword in Kotlin) is an internal class field that stores the property value. An extension property has no access to the internal structure of the class.

kotlin
// ❌ ERROR: extension property cannot have a backing field
var String.cachedValue: String
    get() = "computed"
    set(value) {
        field = value // field is not accessible!
    }

// ✅ CORRECT: use external storage
val cache = MutableMap<String, String>()

var String.cachedValue: String
    get() = cache[this] ?: ""
    set(value) { cache[this] = value }

An external Map in the example solves the storage problem but creates another one — a memory leak. Values obtained through an extension property live in the Map forever if not cleaned up. This limitation makes extension properties unsuitable for caching or storing temporary data.

For caching, it is recommended to use a WeakHashMap or mechanisms with automatic cleanup. JetBrains recommends avoiding the use of var extension properties with external storage in production code without careful lifecycle management.

Extension property vs extension function: when to choose what

The choice between an extension property and an extension function depends on semantics: a property describes a characteristic of an object, while a function describes an action. The Uniform Access Principle states: the client should not know whether a value is computed or stored. If the value can be represented as a characteristic (length, size, status) — use a property.

CriterionExtension propertyExtension function
CallWithout parentheses: obj.propertyWith parentheses: obj.function()
SemanticsCharacteristic, attributeAction, operation
Backing fieldNot supportedNot applicable
ParametersOnly getter/setterAny parameters
PerformanceSame (static method)Same (static method)
Exampletext.lengthtext.isEmail()

The rule is simple: if the operation takes parameters — use an extension function. If it is a simple computed value without parameters — use an extension property. According to the Android Architecture Guide (Google, 2025), preference should be given to extension properties for data access and extension functions for operations with side effects.

Mutable extension property with var and setter

An extension property with the var keyword supports a setter, but without the ability to store a value — the setter usually performs a side effect or saves data to an external store. The syntax is similar to mutable class properties.

kotlin
// Mutable extension property with setter
var StringBuilder.lastChar: Char
    get() = this[length - 1]
    set(value) {
        this.setCharAt(length - 1, value)
    }

val sb = StringBuilder("Kotlin")
println(sb.lastChar) // n
sb.lastChar = '!'
println(sb) // Kotli!

The lastChar property is a classic example from the Kotlin documentation. The getter returns the last character of StringBuilder, the setter replaces it with a new value. Note: the state is stored in the StringBuilder itself (via setCharAt), not in a separate field — this is a correct use of an extension property.

Practical examples of extension properties

In real projects, extension properties are most often used to simplify access to collection data, to calculate sizes or statuses of UI elements, and to create a convenient API on top of existing classes. The Kotlin standard library actively uses this mechanism: size, indices, lastIndex for collections are extension properties.

kotlin
// Extension properties for collections
val List<Int>.sumFast: Int
    get() = fold(0) { acc, i -> acc + i }

val String.half: String
    get() = this.substring(0, length / 2)

// Extension property for Android View
val View.isVisible: Boolean
    get() = visibility == View.VISIBLE

// Null check via safe receiver
val String?.isNullOrBlank: Boolean
    get() = this == null || this.isBlank()

The extension property isVisible for View is an example every Android developer should know. Instead of view.visibility == View.VISIBLE, you can write view.isVisible. This is not only shorter but also reads like natural language: "if the view is visible". Despite their simplicity, such properties significantly improve code readability.

Frequently Asked Questions

Can an extension property be declared for a companion object?

No, extension properties cannot be declared for a companion object or an object declaration. The extension mechanism applies only to classes, interfaces, and nullable types. For object, use regular top-level functions.

How does an extension property differ from an inline property?

An inline property (with the inline modifier) is a Kotlin mechanism for calling a getter/setter without creating a property object. An extension property is always compiled into a static method, while an inline property is compiled into a call without a wrapper. They solve different problems: an extension property adds a property to an existing type, while inline optimizes calls to its own properties.

Do extension properties support annotations?

Yes, an extension property can have annotations, but only at the declaration level. You cannot annotate the getter or setter of an extension property separately — unlike regular class properties. Example: @JvmName("getIsValid") val String.isValid get() = true.

Can an extension property be used with a class's companion object?

No, extension properties cannot be declared with a companion object as a receiver. This is a language limitation — an extension property only works with type instances, while a companion object is a static context. Use top-level extension functions or constants.

Does an extension property affect APK size?

Minimally. Each extension property adds one static getter method (and optionally a setter) to the compiled bytecode. For comparison, creating a wrapper class with the same property adds an entire class. Extension properties are a lighter approach to extending functionality.

Summary

  • Extension property — a computed property for an existing type without inheritance
  • No backing field — state is not stored, only computed through a getter
  • var with setter — possible, but requires external storage for writing data
  • Syntax — val/var with receiver type and mandatory getter
  • Performance — zero overhead, compiles into a static method
  • Usage — computed characteristics: length, status, size, checks
  • Limitation — not suitable for storing state, caching without memory management

We will develop a mobile application turnkey

IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.

Discuss the project

Read also