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 initializationconst val= a special kind ofvalfor 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 constantsval MY_CONST-> unusual, because uppercase suggests a constant butvalis only read-onlyval 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:
valmeans: this box gets one value, and you cannot replace it laterconst valmeans: this box is permanently filled with a simple value that was known before the program even started running
Another way to think about it:
valis a locked containerconst valis 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:
StringIntDoubleBoolean- other primitive-like compile-time values
If Kotlin has to run code to get the value, then it is no longer a const val.
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_USERSfor constantscurrentUserfor 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_NAMEis a constantlaunchTimeis 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.
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
valis 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
| Feature | const val | val |
|---|---|---|
| Reassignable | No | No |
| Compile-time constant | Yes | Not necessarily |
| Can use runtime computation | No | Yes |
| Naming convention | UPPER_SNAKE_CASE | camelCase |
| Good for annotations and fixed literals | Yes | Usually no |
Top-level vs object vs companion object
| Location | When to use it | Example |
|---|---|---|
| Top-level | Constant does not belong to a specific class | const val API_PORT = 8080 |
object | Group related constants together | object HttpHeaders |
companion object | Constant belongs to a class | User.DEFAULT_ROLE |
Your original options compared
| Option | Code | Recommended? | Reason |
|---|---|---|---|
| 1 | val MY_CONST = "something" | Usually no | Uppercase name suggests a true constant, but val does not express that clearly |
| 2 | const val MY_CONST = "something" | Yes | Best choice for a real compile-time constant |
| 3 | val myConst = "something" | Yes, if not a true constant | Good style for a normal read-only property |
Cheat Sheet
Quick rules
- Use
const valfor compile-time constants. - Use
valfor read-only values that are computed at runtime or are unsupported byconst. - Name
const valwithUPPER_SNAKE_CASE. - Name normal
valproperties withcamelCase. - 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:
- Is the value fixed?
- Is it known at compile time?
- 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.
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
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.