Question

Kotlin Constants: Recommended Ways to Declare and Name Them

kotlinconstants

Question

In Kotlin, what is the recommended way to declare constants, and what naming convention should be used?

For example, inside a companion object, which style is preferred?

companion object {
    // 1
    val MY_CONST = "something"

    // 2
    const val MY_CONST = "something"

    // 3
    val myConst = "something"
}

Should one of these be used, or is there a better Kotlin-style approach?

Short Answer

By the end of this page, you will understand how constants are usually declared in Kotlin, when to use const val instead of val, where constants should live, and how Kotlin naming conventions differ for true constants versus regular read-only properties.

Concept

What is a constant in Kotlin?

In Kotlin, a constant usually means a value that:

  • never changes
  • is known at compile time
  • can be inlined by the compiler

For this, Kotlin provides const val.

const val APP_NAME = "MyApp"

A regular val is read-only, but it is not automatically a compile-time constant.

val appName = "MyApp"

This means:

  • val = cannot be reassigned after initialization
  • const val = a special kind of val for compile-time constants

Why this matters

Choosing between val and const val affects:

  • clarity: other developers can immediately see whether a value is a true constant
  • usage: some places require compile-time constants, such as annotations
  • style: Kotlin has different naming conventions for constants and regular properties

Recommended Kotlin style

Use const val when the value is a true compile-time constant

companion object {
    const val MY_CONST = "something"
}

This is the most idiomatic choice when:

  • the value is a primitive or String
  • the value is known at compile time
  • you want it to behave like a real constant

Use val for read-only values that are not compile-time constants

companion object {
    val myValue = buildValue()
}

If the value is computed, created from a function call, or not allowed in const val, use val.

Naming convention

Kotlin convention is usually:

  • UPPER_SNAKE_CASE for const val
  • camelCase for regular properties, including val

Examples:

const val MAX_RETRIES = 3
val defaultName = "Guest"

So from your examples:

  • const val MY_CONST -> recommended for true constants
  • val MY_CONST -> unusual, because uppercase suggests a constant but val is only read-only
  • val myConst -> fine for a normal read-only property, not a compile-time constant

Where constants are commonly declared

Kotlin constants are often placed in:

  • a top-level declaration
  • an object
  • a companion object

For many cases, top-level constants are the simplest option:

const val API_VERSION = "v1"

Use a companion object when the constant logically belongs to a class.

class User {
    companion object {
        const val TYPE_ADMIN = "admin"
    }
}

Mental Model

Think of val and const val like two kinds of labels on boxes:

  • val means: this box gets one value, and you cannot replace it later
  • const val means: this box is permanently filled with a simple value that was known before the program even started running

Another way to think about it:

  • val is a locked container
  • const val is text printed directly into the program at compile time

That is why const val is stricter. Kotlin only allows it for simple values such as:

  • String
  • Int
  • Double
  • Boolean
  • other primitive-like compile-time values

If Kotlin has to run code to get the value, then it is no longer a const val.

Take Quiz

Syntax and Examples

Core syntax

const val

Use this for real compile-time constants:

const val BASE_URL = "https://api.example.com"
const val MAX_COUNT = 10

val

Use this for read-only properties:

val username = "alice"
val createdAt = System.currentTimeMillis()

Inside an object

object Config {
    const val API_KEY_HEADER = "X-API-Key"
    val timeoutMillis = 5000L
}

Inside a companion object

class ApiClient {
    companion object {
        const val DEFAULT_TIMEOUT = 3000
        val defaultHeaders = listOf("Accept: application/json")
    }
}

Top-level constant

const val DATABASE_NAME = "app.db"

This is often the cleanest option when the constant does not belong to a specific class.

Example: when const val works

class Messages {
    companion object {
        const val WELCOME = "Hello"
    }
}

This is valid because the value is a compile-time String literal.

Example: when const val does not work

class Messages {
    companion object {
        val WELCOME = "Hello " + System.currentTimeMillis()
    }
}

This must be val, not const val, because the value depends on runtime computation.

Naming examples

const val MAX_USERS = 100
const val DEFAULT_LANGUAGE = "en"

val currentUser = "Alice"
val maxUsersFromConfig = 100

Use:

  • MAX_USERS for constants
  • currentUser for normal properties

Step by Step Execution

Traceable example

class AppConfig {
    companion object {
        const val APP_NAME = "DemoApp"
        val launchTime = System.currentTimeMillis()
    }
}

fun main() {
    println(AppConfig.APP_NAME)
    println(AppConfig.launchTime)
}

What happens step by step

1. Kotlin sees const val APP_NAME = "DemoApp"

  • This is a compile-time constant.
  • The value is simple and known immediately.
  • Kotlin treats it as a true constant.

2. Kotlin sees val launchTime = System.currentTimeMillis()

  • This is read-only, but not a compile-time constant.
  • The value is created when the program runs.
  • Kotlin cannot mark this as const.

3. main() prints AppConfig.APP_NAME

  • The constant value is accessed directly.
  • It is always "DemoApp".

4. main() prints AppConfig.launchTime

  • This value was computed at runtime.
  • It depends on the time when it was initialized.

Key lesson

Even though both are read-only, they are not the same kind of value:

  • APP_NAME is a constant
  • launchTime is a read-only property

Real World Use Cases

Common places constants are used

Configuration keys

const val PREF_USER_TOKEN = "user_token"
const val PREF_THEME = "theme"

These are fixed strings used in settings or shared preferences.

API field names and headers

const val HEADER_AUTHORIZATION = "Authorization"
const val CONTENT_TYPE_JSON = "application/json"

Useful when the same literal appears in many places.

Intent extras or navigation keys

const val EXTRA_USER_ID = "extra_user_id"

This avoids typos when passing values between screens.

Limits and defaults

const val MAX_LOGIN_ATTEMPTS = 5
const val DEFAULT_PAGE_SIZE = 20

These values are fixed business rules or defaults.

Annotation arguments

const val is required in places where Kotlin expects a compile-time constant.

const val ROUTE = "/users"

This is one of the practical reasons to prefer const val for true constants.

Take Quiz

Real Codebase Usage

How developers commonly use constants in real projects

1. Group related constants in object

object ApiConstants {
    const val BASE_URL = "https://api.example.com"
    const val USERS_PATH = "/users"
}

This keeps related values organized.

2. Use top-level constants for file-wide shared values

const val SECONDS_IN_MINUTE = 60

This is simple and avoids unnecessary wrappers.

3. Use companion object for class-specific constants

class UserRepository {
    companion object {
        const val CACHE_KEY = "user_repo_cache"
    }
}

This is useful when the constant belongs conceptually to that class.

4. Use regular val for computed read-only values

object RuntimeConfig {
    val environment = System.getenv("APP_ENV") ?: "dev"
}

This is read-only but not a constant.

5. Use constants to remove magic values

Instead of this:

if (retries > 3) {
    println("Too many retries")
}

developers often write:

const val MAX_RETRIES = 3

if (retries > MAX_RETRIES) {
    println("Too many retries")
}

This improves readability and maintenance.

6. Combine constants with validation and guard clauses

const val MIN_PASSWORD_LENGTH = 8

fun validatePassword(password: String) {
    if (password.length < MIN_PASSWORD_LENGTH) {
        throw IllegalArgumentException("Password too short")
    }
}

Constants make validation rules clear and reusable.

Common Mistakes

1. Using uppercase names for regular val

Broken style example:

companion object {
    val MY_CONST = "something"
}

Why this is a problem:

  • the uppercase name suggests a true constant
  • but val is only read-only, not necessarily compile-time constant

Better:

companion object {
    const val MY_CONST = "something"
}

Or, if it is not a compile-time constant:

companion object {
    val myConst = createValue()
}

2. Trying to use const val with runtime values

Broken code:

const val START_TIME = System.currentTimeMillis()

This fails because System.currentTimeMillis() is only known at runtime.

Correct:

val startTime = System.currentTimeMillis()

3. Putting every constant in a companion object

Sometimes a top-level constant is simpler.

Less clear:

class AppConstants {
    companion object {
        const val VERSION = "1.0"
    }
}

Often better:

const val VERSION = "1.0"

Use companion object only when the constant belongs to the class.

4. Confusing immutability with compile-time constants

val name = "Alice"

This is immutable after assignment, but that does not automatically make it a const val.

5. Using const val for unsupported types

Broken code:

const val NAMES = listOf("A", "B")

const val only works with compile-time constant types, not collections.

Correct:

val names = listOf("A", "B")

Comparisons

const val vs val

Featureconst valval
ReassignableNoNo
Compile-time constantYesNot necessarily
Can use runtime computationNoYes
Naming conventionUPPER_SNAKE_CASEcamelCase
Good for annotations and fixed literalsYesUsually no

Top-level vs object vs companion object

LocationWhen to use itExample
Top-levelConstant does not belong to a specific classconst val API_PORT = 8080
objectGroup related constants togetherobject HttpHeaders
companion objectConstant belongs to a classUser.DEFAULT_ROLE

Your original options compared

OptionCodeRecommended?Reason
1val MY_CONST = "something"Usually noUppercase name suggests a true constant, but val does not express that clearly
2const val MY_CONST = "something"YesBest choice for a real compile-time constant
3val myConst = "something"Yes, if not a true constantGood style for a normal read-only property
Take Quiz

Cheat Sheet

Quick rules

  • Use const val for compile-time constants.
  • Use val for read-only values that are computed at runtime or are unsupported by const.
  • Name const val with UPPER_SNAKE_CASE.
  • Name normal val properties with camelCase.
  • Prefer top-level constants unless the constant clearly belongs to a class or group.

Syntax

const val MAX_SIZE = 100
val currentSize = getSize()

Valid const val examples

const val APP_NAME = "Demo"
const val RETRY_LIMIT = 3
const val PI_APPROX = 3.14
const val ENABLE_LOGGING = true

Invalid const val examples

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

Good placement choices

const val VERSION = "1.0"

object Keys {
    const val TOKEN = "token"
}

class User {
    companion object {
        const val DEFAULT_ROLE = "guest"
    }
}

Naming guide

const val MAX_RETRIES = 5
val maxRetriesFromServer = 5

Simple decision rule

Ask:

  1. Is the value fixed?
  2. Is it known at compile time?
  3. Is it a supported constant type?

If yes to all three, use const val. Otherwise, use val.

FAQ

Should I always use const val instead of val in Kotlin?

No. Use const val only for true compile-time constants. Use val for read-only values that are computed at runtime or use unsupported types.

What is the Kotlin naming convention for constants?

Use UPPER_SNAKE_CASE for const val, such as MAX_RETRIES. Use camelCase for regular val properties.

Is val a constant in Kotlin?

Not exactly. val means read-only after initialization, but it may still be initialized at runtime, so it is not necessarily a compile-time constant.

Can I declare const val inside a class?

Not as a normal instance property. It is typically declared at the top level, inside an object, or inside a companion object.

When should I use a top-level constant in Kotlin?

Use a top-level constant when the value does not logically belong to any specific class.

Can const val hold a list or object?

No. const val only supports compile-time constant values such as strings and primitive values.

Which of these is most idiomatic: val MY_CONST, const val MY_CONST, or val myConst?

For a true constant, const val MY_CONST is most idiomatic. If it is only a read-only property, use val myConst.

Take Quiz

Mini Project

Description

Create a small Kotlin configuration file for an app. The goal is to practice deciding which values should be const val and which should remain regular val properties. This mirrors real projects where some values are fixed constants and others are loaded or computed at runtime.

Goal

Build a simple app settings structure that uses const val for true constants and val for runtime values.

Requirements

  • Create at least two true constants using const val
  • Group at least one set of constants inside an object
  • Add one runtime-computed read-only value using val
  • Print all values from a main() function
Take Quiz

Keep learning

Related questions

View more