Spring Boot
Kotlin
@Value Annotation
Troubleshooting
Configuration

Spring Boot with Kotlin - Value annotation not working as expected

Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms

Introduction

When @Value appears broken in a Kotlin Spring Boot project, the root cause is usually not Kotlin itself. It is usually one of a few practical issues: the class is not Spring-managed, the property key is wrong, the ${...} expression was written incorrectly for Kotlin strings, or @Value is being used where @ConfigurationProperties would be a better fit.

Kotlin does make some of these mistakes more visible. Constructor injection, non-null types, and immutable properties expose configuration problems sooner than older Java-style field injection patterns.

Make Sure the Bean Is Actually Managed by Spring

@Value works only when Spring creates the object:

kotlin
1import org.springframework.beans.factory.annotation.Value
2import org.springframework.stereotype.Component
3
4@Component
5class ApiSettings(
6    @Value("\${app.api.base-url}")
7    val baseUrl: String
8)

If you instantiate the class manually with ApiSettings(...), no injection happens. That is the first thing to verify before changing annotations or properties files.

Kotlin Strings Need Escaped ${...} in Annotations

This is one of the most Kotlin-specific mistakes. Because Kotlin uses $ for string interpolation, the @Value expression must escape the dollar sign:

kotlin
@Value("\${app.mode}")

Not this:

kotlin
@Value("${app.mode}")

The second form is interpreted by Kotlin as string interpolation, not as the Spring placeholder you intended.

Prefer Constructor Injection in Kotlin

Constructor injection works naturally with immutable Kotlin code:

kotlin
1import org.springframework.beans.factory.annotation.Value
2import org.springframework.stereotype.Component
3
4@Component
5class ModeConfig(
6    @Value("\${app.mode:dev}")
7    val mode: String
8)

This is usually safer than field injection with lateinit, because the dependency is provided at construction time and the property can remain a val.

Field injection can work:

kotlin
1@Component
2class LegacyConfig {
3    @Value("\${app.mode}")
4    lateinit var mode: String
5}

But it is easier to misuse, especially in tests and manual object creation.

Verify Property Keys and Profiles

A lot of @Value failures are simple configuration mismatches:

properties
app.api.base-url=https://api.example.com
app.mode=prod

Then check the active profile explicitly:

bash
java -jar app.jar --spring.profiles.active=dev

If the wrong profile is active, the property may genuinely not exist in the resolved environment. Before assuming the annotation is broken, confirm:

  • the property key spelling
  • the active profile
  • the property source that should provide the value

Use @ConfigurationProperties for Grouped Settings

If you have many related settings, multiple @Value annotations are usually the wrong abstraction. A typed properties class is clearer:

kotlin
1import org.springframework.boot.context.properties.ConfigurationProperties
2
3@ConfigurationProperties(prefix = "app.auth")
4data class AuthProperties(
5    var issuer: String = "",
6    var audience: String = "",
7    var tokenTtlSeconds: Long = 3600
8)

Then enable it in configuration:

kotlin
1import org.springframework.boot.context.properties.EnableConfigurationProperties
2import org.springframework.context.annotation.Configuration
3
4@Configuration
5@EnableConfigurationProperties(AuthProperties::class)
6class AuthConfig

This is usually easier to validate, test, and maintain than a scattering of unrelated @Value expressions.

Common Pitfalls

The biggest Kotlin-specific mistake is forgetting to escape the dollar sign in the placeholder string. If the annotation uses "${...}" instead of "\${...}", the expression is wrong before Spring even sees it.

Another common issue is putting @Value on a class that Spring does not manage. Manual instantiation bypasses the entire injection process.

Developers also use @Value on too many individual fields when the configuration really belongs in a typed properties object. That makes the code harder to read and harder to validate.

Finally, do not ignore the simple possibility of a bad property key or wrong profile. Those remain the most common failures in ordinary Spring Boot projects.

Summary

  • '@Value works only on Spring-managed objects.'
  • In Kotlin, write placeholders as "\${...}", not "${...}".
  • Constructor injection is the cleanest default for Kotlin Spring code.
  • Check property keys and active profiles before deeper debugging.
  • Use @ConfigurationProperties when several related settings belong together.

Course
Intermediate
27 lessons
14 hours
OOD Fundamentals

Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.

View the course
Data Structures & Algorithms practice on Codemia

Step through 300+ coding interview problems with animated visualisers that show the data structure changing as the code runs. The Blind 75 are free.

Practice algorithms