0
# Configuration Management
1
2
Application configuration system supporting multiple formats and sources with hierarchical merging capabilities. Provides flexible configuration management for Ktor applications with support for environment variables, config files, and programmatic configuration.
3
4
## Capabilities
5
6
### Application Configuration Interface
7
8
Core interface for accessing hierarchical configuration data.
9
10
```kotlin { .api }
11
/**
12
* Represents application config node with hierarchical structure
13
*/
14
interface ApplicationConfig {
15
/** Get a property value, throws if missing */
16
fun property(path: String): ApplicationConfigValue
17
/** Get a property value or null if missing */
18
fun propertyOrNull(path: String): ApplicationConfigValue?
19
/** Get a nested config section */
20
fun config(path: String): ApplicationConfig
21
/** Get a list of config sections */
22
fun configList(path: String): List<ApplicationConfig>
23
/** Get all keys at this config level */
24
fun keys(): Set<String>
25
/** Convert config to a map representation */
26
fun toMap(): Map<String, Any?>
27
}
28
```
29
30
### Configuration Values
31
32
Interface for accessing typed configuration values with conversion support.
33
34
```kotlin { .api }
35
/**
36
* Represents a configuration value with type information
37
*/
38
interface ApplicationConfigValue {
39
/** The type of this configuration value */
40
val type: Type
41
/** Get value as string */
42
fun getString(): String
43
/** Get value as list of strings */
44
fun getList(): List<String>
45
/** Get value as map */
46
fun getMap(): Map<String, Any?>
47
/** Get value converted to specified type */
48
fun getAs(type: TypeInfo): Any?
49
50
/**
51
* Type enumeration for configuration values
52
*/
53
enum class Type {
54
NULL,
55
SINGLE,
56
LIST,
57
OBJECT
58
}
59
}
60
```
61
62
### Map-Based Configuration
63
64
Mutable configuration implementation backed by hash map for programmatic configuration.
65
66
```kotlin { .api }
67
/**
68
* Mutable application config backed by hash map
69
*/
70
open class MapApplicationConfig : ApplicationConfig {
71
/** Set a single string value */
72
fun put(path: String, value: String)
73
/** Set multiple string values */
74
fun put(path: String, values: Iterable<String>)
75
/** Remove a configuration value */
76
fun remove(path: String)
77
/** Check if path exists */
78
fun containsKey(path: String): Boolean
79
/** Clear all configuration */
80
fun clear()
81
}
82
```
83
84
### Configuration Loading
85
86
System for loading configuration from various sources.
87
88
```kotlin { .api }
89
/**
90
* Interface for loading application configuration
91
*/
92
interface ConfigLoader {
93
/** Load configuration from specified path */
94
fun load(path: String?): ApplicationConfig?
95
96
companion object {
97
/** Load configuration using default loaders */
98
fun load(path: String? = null): ApplicationConfig
99
}
100
}
101
```
102
103
### Configuration Merging
104
105
Utilities for combining multiple configuration sources with precedence rules.
106
107
```kotlin { .api }
108
/**
109
* Merge this configuration with another, other takes precedence
110
*/
111
fun ApplicationConfig.mergeWith(other: ApplicationConfig): ApplicationConfig
112
113
/**
114
* Merge this configuration with another, this takes precedence
115
*/
116
fun ApplicationConfig.withFallback(other: ApplicationConfig): ApplicationConfig
117
```
118
119
### Configuration Exceptions
120
121
Exception classes for configuration-related errors.
122
123
```kotlin { .api }
124
/**
125
* Thrown when application is misconfigured
126
*/
127
class ApplicationConfigurationException(message: String, cause: Throwable? = null) : Exception(message, cause)
128
```
129
130
## Usage Examples
131
132
### Basic Configuration Access
133
134
```kotlin
135
import io.ktor.server.application.*
136
import io.ktor.server.config.*
137
138
fun Application.configureFromConfig() {
139
val config = environment.config
140
141
// Access simple properties
142
val serverPort = config.property("server.port").getString().toInt()
143
val serverHost = config.property("server.host").getString()
144
val debugMode = config.propertyOrNull("debug")?.getString()?.toBoolean() ?: false
145
146
// Access nested configuration
147
val databaseConfig = config.config("database")
148
val dbUrl = databaseConfig.property("url").getString()
149
val dbDriver = databaseConfig.property("driver").getString()
150
151
// Access list configuration
152
val allowedHosts = config.property("security.allowedHosts").getList()
153
154
// Access complex nested structures
155
val features = config.configList("features")
156
features.forEach { featureConfig ->
157
val name = featureConfig.property("name").getString()
158
val enabled = featureConfig.property("enabled").getString().toBoolean()
159
println("Feature $name: $enabled")
160
}
161
}
162
```
163
164
### Programmatic Configuration
165
166
```kotlin
167
import io.ktor.server.config.*
168
169
fun createProgrammaticConfig(): ApplicationConfig {
170
val config = MapApplicationConfig()
171
172
// Set single values
173
config.put("server.port", "8080")
174
config.put("server.host", "localhost")
175
config.put("debug", "true")
176
177
// Set list values
178
config.put("security.allowedHosts", listOf("localhost", "127.0.0.1", "::1"))
179
180
// Set nested values using dot notation
181
config.put("database.url", "jdbc:h2:mem:test")
182
config.put("database.driver", "org.h2.Driver")
183
config.put("database.user", "sa")
184
config.put("database.password", "")
185
186
return config
187
}
188
```
189
190
### Configuration Merging
191
192
```kotlin
193
import io.ktor.server.config.*
194
195
fun mergeConfigurations(): ApplicationConfig {
196
// Load base configuration from file
197
val baseConfig = ConfigLoader.load("application.conf")
198
199
// Create environment-specific overrides
200
val envConfig = MapApplicationConfig().apply {
201
put("server.port", System.getenv("PORT") ?: "8080")
202
put("database.url", System.getenv("DATABASE_URL") ?: "jdbc:h2:mem:dev")
203
}
204
205
// Create development-specific settings
206
val devConfig = MapApplicationConfig().apply {
207
put("debug", "true")
208
put("logging.level", "DEBUG")
209
}
210
211
// Merge configurations with precedence
212
// envConfig overrides baseConfig, devConfig overrides both
213
return baseConfig
214
.mergeWith(envConfig)
215
.mergeWith(devConfig)
216
}
217
```
218
219
### Type-Safe Configuration Access
220
221
```kotlin
222
import io.ktor.server.config.*
223
224
// Extension functions for common configuration patterns
225
val ApplicationConfig.serverPort: Int
226
get() = property("server.port").getString().toInt()
227
228
val ApplicationConfig.serverHost: String
229
get() = property("server.host").getString()
230
231
val ApplicationConfig.isDebugMode: Boolean
232
get() = propertyOrNull("debug")?.getString()?.toBoolean() ?: false
233
234
val ApplicationConfig.databaseUrl: String
235
get() = config("database").property("url").getString()
236
237
fun ApplicationConfig.getStringList(path: String): List<String> =
238
property(path).getList()
239
240
fun ApplicationConfig.getOptionalString(path: String): String? =
241
propertyOrNull(path)?.getString()
242
243
fun ApplicationConfig.getOptionalInt(path: String): Int? =
244
propertyOrNull(path)?.getString()?.toIntOrNull()
245
246
// Usage
247
fun Application.configureWithExtensions() {
248
val config = environment.config
249
250
val port = config.serverPort
251
val host = config.serverHost
252
val debug = config.isDebugMode
253
val dbUrl = config.databaseUrl
254
255
val allowedOrigins = config.getStringList("cors.allowedOrigins")
256
val maxRequestSize = config.getOptionalInt("limits.maxRequestSize") ?: 1048576
257
}
258
```
259
260
### Environment-Based Configuration
261
262
```kotlin
263
import io.ktor.server.config.*
264
265
fun createEnvironmentConfig(): ApplicationConfig {
266
val config = MapApplicationConfig()
267
268
// Database configuration from environment
269
config.put("database.url",
270
System.getenv("DATABASE_URL") ?: "jdbc:h2:mem:test")
271
config.put("database.user",
272
System.getenv("DB_USER") ?: "sa")
273
config.put("database.password",
274
System.getenv("DB_PASSWORD") ?: "")
275
config.put("database.maxPoolSize",
276
System.getenv("DB_POOL_SIZE") ?: "10")
277
278
// Server configuration from environment
279
config.put("server.port",
280
System.getenv("PORT") ?: "8080")
281
config.put("server.host",
282
System.getenv("HOST") ?: "0.0.0.0")
283
284
// Feature flags from environment
285
config.put("features.rateLimiting",
286
System.getenv("ENABLE_RATE_LIMITING") ?: "false")
287
config.put("features.caching",
288
System.getenv("ENABLE_CACHING") ?: "true")
289
290
// Logging configuration
291
config.put("logging.level",
292
System.getenv("LOG_LEVEL") ?: "INFO")
293
config.put("logging.appenders",
294
listOf("console", "file"))
295
296
return config
297
}
298
```
299
300
### Configuration Validation
301
302
```kotlin
303
import io.ktor.server.config.*
304
305
fun validateConfiguration(config: ApplicationConfig) {
306
try {
307
// Validate required properties exist
308
val requiredProperties = listOf(
309
"server.port",
310
"server.host",
311
"database.url",
312
"database.driver"
313
)
314
315
requiredProperties.forEach { path ->
316
config.property(path) // Will throw if missing
317
}
318
319
// Validate port is valid number
320
val port = config.property("server.port").getString().toInt()
321
require(port in 1..65535) { "Port must be in range 1-65535, got $port" }
322
323
// Validate database URL format
324
val dbUrl = config.property("database.url").getString()
325
require(dbUrl.startsWith("jdbc:")) { "Database URL must start with jdbc:" }
326
327
// Validate optional properties
328
config.propertyOrNull("server.ssl.enabled")?.let { ssl ->
329
if (ssl.getString().toBoolean()) {
330
config.property("server.ssl.keyStore") // Must exist if SSL enabled
331
config.property("server.ssl.keyStorePassword")
332
}
333
}
334
335
} catch (e: Exception) {
336
throw ApplicationConfigurationException("Configuration validation failed", e)
337
}
338
}
339
```