or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconfiguration.mdengine.mdindex.mdrequest-response.mdrouting.md

configuration.mddocs/

0

# Configuration System

1

2

Ktor's configuration system provides flexible application configuration management through multiple sources including files, environment variables, and programmatic configuration. The system supports hierarchical configuration with type-safe access and validation.

3

4

## ApplicationConfig Interface

5

6

### Core Configuration Interface

7

8

```kotlin { .api }

9

interface ApplicationConfig {

10

fun property(path: String): ApplicationConfigValue

11

fun propertyOrNull(path: String): ApplicationConfigValue?

12

fun config(path: String): ApplicationConfig

13

fun configList(path: String): List<ApplicationConfig>

14

fun keys(): Set<String>

15

fun toMap(): Map<String, Any?>

16

}

17

```

18

19

### Configuration Value Interface

20

21

```kotlin { .api }

22

interface ApplicationConfigValue {

23

val type: Type

24

25

fun getString(): String

26

fun getList(): List<String>

27

fun getInt(): Int

28

fun getLong(): Long

29

fun getFloat(): Float

30

fun getDouble(): Double

31

fun getBoolean(): Boolean

32

}

33

```

34

35

### Basic Configuration Usage

36

37

```kotlin { .api }

38

// Access configuration properties

39

fun Application.loadConfig() {

40

val config = environment.config

41

42

// String properties

43

val appName = config.property("app.name").getString()

44

val version = config.propertyOrNull("app.version")?.getString() ?: "1.0.0"

45

46

// Numeric properties

47

val port = config.property("server.port").getInt()

48

val timeout = config.property("server.timeout").getLong()

49

val rate = config.property("app.rate").getDouble()

50

51

// Boolean properties

52

val debugMode = config.property("app.debug").getBoolean()

53

val enableLogging = config.propertyOrNull("logging.enabled")?.getBoolean() ?: true

54

55

// List properties

56

val allowedHosts = config.property("server.allowedHosts").getList()

57

val modules = config.propertyOrNull("app.modules")?.getList() ?: emptyList()

58

}

59

```

60

61

## Configuration Implementations

62

63

### MapApplicationConfig

64

65

```kotlin { .api }

66

// Configuration backed by Map

67

class MapApplicationConfig(vararg values: Pair<String, String>) : ApplicationConfig {

68

constructor(map: Map<String, String>)

69

70

// Add or update configuration values

71

fun put(key: String, value: String)

72

fun putAll(values: Map<String, String>)

73

}

74

75

// Create programmatic configuration

76

val config = MapApplicationConfig(

77

"app.name" to "MyKtorApp",

78

"server.port" to "8080",

79

"server.host" to "0.0.0.0",

80

"database.url" to "jdbc:h2:mem:test",

81

"database.driver" to "org.h2.Driver",

82

"logging.level" to "INFO"

83

)

84

85

// Use with application environment

86

val environment = applicationEnvironment {

87

this.config = config

88

}

89

```

90

91

### MergedApplicationConfig

92

93

```kotlin { .api }

94

// Configuration that merges multiple configs with precedence

95

class MergedApplicationConfig(

96

vararg configs: ApplicationConfig

97

) : ApplicationConfig {

98

// Later configs override earlier ones

99

}

100

101

// Example: Environment variables override file config

102

val fileConfig = HoconApplicationConfig(ConfigFactory.load())

103

val envConfig = MapApplicationConfig(System.getenv().mapKeys { "env.${it.key}" })

104

val merged = MergedApplicationConfig(fileConfig, envConfig)

105

```

106

107

## HOCON Configuration Support

108

109

### HoconApplicationConfig

110

111

```kotlin { .api }

112

// Configuration using Typesafe Config (HOCON format)

113

class HoconApplicationConfig(

114

private val config: Config

115

) : ApplicationConfig {

116

117

constructor(configPath: String) : this(ConfigFactory.load(configPath))

118

119

// Access nested configuration

120

override fun config(path: String): ApplicationConfig {

121

return HoconApplicationConfig(config.getConfig(path))

122

}

123

}

124

125

// Load HOCON configuration

126

val config = HoconApplicationConfig(ConfigFactory.load())

127

128

// application.conf example:

129

/*

130

app {

131

name = "MyKtorApp"

132

version = "1.0.0"

133

debug = false

134

135

server {

136

port = 8080

137

host = "0.0.0.0"

138

ssl {

139

enabled = false

140

keyStore = "keystore.jks"

141

keyAlias = "mykey"

142

}

143

}

144

145

database {

146

url = "jdbc:postgresql://localhost:5432/mydb"

147

driver = "org.postgresql.Driver"

148

user = "dbuser"

149

password = "dbpass"

150

151

pool {

152

maxSize = 20

153

minIdle = 5

154

maxLifetime = 1800000

155

}

156

}

157

158

logging {

159

level = "INFO"

160

appenders = ["console", "file"]

161

162

file {

163

path = "logs/app.log"

164

maxSize = "10MB"

165

maxHistory = 30

166

}

167

}

168

}

169

*/

170

```

171

172

### Hierarchical Configuration Access

173

174

```kotlin { .api }

175

fun Application.configureFromHocon() {

176

val config = environment.config

177

178

// Access nested configurations

179

val serverConfig = config.config("server")

180

val port = serverConfig.property("port").getInt()

181

val host = serverConfig.property("host").getString()

182

183

val sslConfig = serverConfig.config("ssl")

184

val sslEnabled = sslConfig.property("enabled").getBoolean()

185

186

if (sslEnabled) {

187

val keyStore = sslConfig.property("keyStore").getString()

188

val keyAlias = sslConfig.property("keyAlias").getString()

189

// Configure SSL

190

}

191

192

// Access configuration lists

193

val dbConfigs = config.configList("databases")

194

dbConfigs.forEach { dbConfig ->

195

val url = dbConfig.property("url").getString()

196

val driver = dbConfig.property("driver").getString()

197

// Configure database connection

198

}

199

}

200

```

201

202

## Environment Variable Configuration

203

204

### Environment Integration

205

206

```kotlin { .api }

207

// Create configuration from environment variables

208

fun createEnvironmentConfig(): ApplicationConfig {

209

val envVars = System.getenv()

210

val configMap = mutableMapOf<String, String>()

211

212

// Map environment variables to config paths

213

envVars.forEach { (key, value) ->

214

when {

215

key.startsWith("KTOR_") -> {

216

val configKey = key.removePrefix("KTOR_")

217

.lowercase()

218

.replace('_', '.')

219

configMap[configKey] = value

220

}

221

}

222

}

223

224

return MapApplicationConfig(configMap)

225

}

226

227

// Example environment variables:

228

// KTOR_SERVER_PORT=8080

229

// KTOR_SERVER_HOST=0.0.0.0

230

// KTOR_DATABASE_URL=jdbc:postgresql://localhost/mydb

231

// KTOR_LOGGING_LEVEL=DEBUG

232

233

// Usage

234

val envConfig = createEnvironmentConfig()

235

val fileConfig = HoconApplicationConfig(ConfigFactory.load())

236

val config = MergedApplicationConfig(fileConfig, envConfig) // Env overrides file

237

```

238

239

### System Properties Integration

240

241

```kotlin { .api }

242

// Create configuration from system properties

243

fun createSystemPropsConfig(): ApplicationConfig {

244

val sysProps = System.getProperties()

245

val configMap = mutableMapOf<String, String>()

246

247

sysProps.forEach { key, value ->

248

if (key.toString().startsWith("ktor.")) {

249

configMap[key.toString()] = value.toString()

250

}

251

}

252

253

return MapApplicationConfig(configMap)

254

}

255

256

// Usage with JVM arguments:

257

// java -Dktor.server.port=8080 -Dktor.debug=true MyApp

258

```

259

260

## Configuration Loaders

261

262

### ConfigLoaders Object

263

264

```kotlin { .api }

265

object ConfigLoaders {

266

fun file(path: String): ApplicationConfig {

267

return HoconApplicationConfig(ConfigFactory.parseFile(File(path)))

268

}

269

270

fun classpath(resource: String): ApplicationConfig {

271

return HoconApplicationConfig(ConfigFactory.parseResources(resource))

272

}

273

274

fun properties(path: String): ApplicationConfig {

275

val props = Properties()

276

File(path).inputStream().use { props.load(it) }

277

return MapApplicationConfig(props.toMap() as Map<String, String>)

278

}

279

280

fun environment(): ApplicationConfig {

281

return createEnvironmentConfig()

282

}

283

284

fun systemProperties(): ApplicationConfig {

285

return createSystemPropsConfig()

286

}

287

}

288

289

// Load configuration from multiple sources

290

val config = MergedApplicationConfig(

291

ConfigLoaders.classpath("application.conf"), // Default config

292

ConfigLoaders.file("config/production.conf"), // Environment-specific

293

ConfigLoaders.environment(), // Environment variables

294

ConfigLoaders.systemProperties() // JVM system properties

295

)

296

```

297

298

## Configuration Decoder

299

300

### MapConfigDecoder

301

302

```kotlin { .api }

303

// Decoder for map-based configurations

304

class MapConfigDecoder {

305

fun decode(map: Map<String, Any?>): ApplicationConfig {

306

return MapApplicationConfig().apply {

307

map.forEach { (key, value) ->

308

when (value) {

309

is String -> put(key, value)

310

is Number -> put(key, value.toString())

311

is Boolean -> put(key, value.toString())

312

is List<*> -> {

313

// Handle list values

314

value.forEachIndexed { index, item ->

315

put("$key.$index", item.toString())

316

}

317

}

318

is Map<*, *> -> {

319

// Handle nested maps

320

@Suppress("UNCHECKED_CAST")

321

val nested = value as Map<String, Any?>

322

nested.forEach { (nestedKey, nestedValue) ->

323

put("$key.$nestedKey", nestedValue.toString())

324

}

325

}

326

}

327

}

328

}

329

}

330

}

331

```

332

333

## Deployment Configuration Extensions

334

335

### Standard Deployment Properties

336

337

```kotlin { .api }

338

// Extension properties for common deployment settings

339

val ApplicationConfig.port: Int

340

get() = propertyOrNull("ktor.deployment.port")?.getInt() ?: 8080

341

342

val ApplicationConfig.host: String

343

get() = propertyOrNull("ktor.deployment.host")?.getString() ?: "0.0.0.0"

344

345

val ApplicationConfig.sslPort: Int?

346

get() = propertyOrNull("ktor.security.ssl.port")?.getInt()

347

348

val ApplicationConfig.developmentMode: Boolean

349

get() = propertyOrNull("ktor.development")?.getBoolean() ?: false

350

351

val ApplicationConfig.rootPath: String

352

get() = propertyOrNull("ktor.deployment.rootPath")?.getString() ?: ""

353

354

// Usage

355

fun Application.configureFromDeployment() {

356

val config = environment.config

357

358

log.info("Starting server on ${config.host}:${config.port}")

359

log.info("Development mode: ${config.developmentMode}")

360

log.info("Root path: ${config.rootPath}")

361

362

config.sslPort?.let { sslPort ->

363

log.info("SSL enabled on port $sslPort")

364

}

365

}

366

```

367

368

### Watch Paths Configuration

369

370

```kotlin { .api }

371

// Configure watch paths for development auto-reload

372

fun ApplicationEnvironmentBuilder.configureWatchPaths(config: ApplicationConfig) {

373

config.propertyOrNull("ktor.deployment.watch")?.getList()?.forEach { path ->

374

watchPaths.add(path)

375

}

376

377

// Or from individual watch entries

378

config.configList("ktor.deployment.watch").forEach { watchConfig ->

379

val path = watchConfig.property("path").getString()

380

watchPaths.add(path)

381

}

382

}

383

384

// application.conf example:

385

/*

386

ktor {

387

deployment {

388

watch = [

389

"src/main/kotlin",

390

"src/main/resources"

391

]

392

393

# Alternative format

394

watch = [

395

{ path = "src/main/kotlin" },

396

{ path = "src/main/resources" }

397

]

398

}

399

}

400

*/

401

```

402

403

## Type-Safe Configuration

404

405

### Configuration Data Classes

406

407

```kotlin { .api }

408

// Define configuration data classes

409

data class ServerConfig(

410

val port: Int,

411

val host: String,

412

val ssl: SslConfig?

413

)

414

415

data class SslConfig(

416

val port: Int,

417

val keyStore: String,

418

val keyPassword: String,

419

val keyAlias: String

420

)

421

422

data class DatabaseConfig(

423

val url: String,

424

val driver: String,

425

val user: String,

426

val password: String,

427

val pool: PoolConfig

428

)

429

430

data class PoolConfig(

431

val maxSize: Int,

432

val minIdle: Int,

433

val maxLifetime: Long

434

)

435

436

// Extension functions for type-safe access

437

fun ApplicationConfig.getServerConfig(): ServerConfig {

438

val serverConfig = config("server")

439

return ServerConfig(

440

port = serverConfig.property("port").getInt(),

441

host = serverConfig.property("host").getString(),

442

ssl = serverConfig.propertyOrNull("ssl")?.let {

443

val sslConfig = serverConfig.config("ssl")

444

SslConfig(

445

port = sslConfig.property("port").getInt(),

446

keyStore = sslConfig.property("keyStore").getString(),

447

keyPassword = sslConfig.property("keyPassword").getString(),

448

keyAlias = sslConfig.property("keyAlias").getString()

449

)

450

}

451

)

452

}

453

454

fun ApplicationConfig.getDatabaseConfig(): DatabaseConfig {

455

val dbConfig = config("database")

456

return DatabaseConfig(

457

url = dbConfig.property("url").getString(),

458

driver = dbConfig.property("driver").getString(),

459

user = dbConfig.property("user").getString(),

460

password = dbConfig.property("password").getString(),

461

pool = dbConfig.config("pool").let { poolConfig ->

462

PoolConfig(

463

maxSize = poolConfig.property("maxSize").getInt(),

464

minIdle = poolConfig.property("minIdle").getInt(),

465

maxLifetime = poolConfig.property("maxLifetime").getLong()

466

)

467

}

468

)

469

}

470

```

471

472

## Configuration Validation

473

474

### Configuration Validation Utilities

475

476

```kotlin { .api }

477

// Validation extension functions

478

fun ApplicationConfigValue.requireInt(min: Int? = null, max: Int? = null): Int {

479

val value = getInt()

480

min?.let { require(value >= it) { "Value must be >= $it, got $value" } }

481

max?.let { require(value <= it) { "Value must be <= $it, got $value" } }

482

return value

483

}

484

485

fun ApplicationConfigValue.requireString(pattern: Regex? = null): String {

486

val value = getString()

487

require(value.isNotBlank()) { "Value cannot be blank" }

488

pattern?.let { require(value.matches(it)) { "Value '$value' doesn't match pattern $it" } }

489

return value

490

}

491

492

fun ApplicationConfig.requireProperty(path: String): ApplicationConfigValue {

493

return propertyOrNull(path) ?: throw IllegalStateException("Required property '$path' not found")

494

}

495

496

// Validation example

497

fun Application.validateConfiguration() {

498

val config = environment.config

499

500

try {

501

// Validate required properties

502

val port = config.requireProperty("server.port").requireInt(min = 1, max = 65535)

503

val host = config.requireProperty("server.host").requireString()

504

val dbUrl = config.requireProperty("database.url")

505

.requireString(Regex("^jdbc:[a-zA-Z0-9]+://.*"))

506

507

log.info("Configuration validated successfully")

508

log.info("Server will start on $host:$port")

509

510

} catch (e: IllegalStateException) {

511

log.error("Configuration validation failed: ${e.message}")

512

throw e

513

} catch (e: IllegalArgumentException) {

514

log.error("Configuration validation failed: ${e.message}")

515

throw e

516

}

517

}

518

```

519

520

## Complete Configuration Example

521

522

### Multi-Environment Configuration

523

524

```kotlin { .api }

525

// Environment-specific configuration loading

526

class ConfigurationManager {

527

528

fun loadConfiguration(environment: String = "development"): ApplicationConfig {

529

val configs = mutableListOf<ApplicationConfig>()

530

531

// Base configuration

532

configs.add(ConfigLoaders.classpath("application.conf"))

533

534

// Environment-specific configuration

535

val envConfigFile = "application-$environment.conf"

536

try {

537

configs.add(ConfigLoaders.classpath(envConfigFile))

538

} catch (e: Exception) {

539

println("Environment config $envConfigFile not found, using defaults")

540

}

541

542

// External configuration file (if exists)

543

val externalConfig = File("config/application.conf")

544

if (externalConfig.exists()) {

545

configs.add(ConfigLoaders.file(externalConfig.path))

546

}

547

548

// Environment variables (highest priority)

549

configs.add(ConfigLoaders.environment())

550

551

// System properties (highest priority)

552

configs.add(ConfigLoaders.systemProperties())

553

554

return MergedApplicationConfig(*configs.toTypedArray())

555

}

556

}

557

558

// Application configuration setup

559

fun main() {

560

val environment = System.getenv("APP_ENV") ?: "development"

561

val configManager = ConfigurationManager()

562

val config = configManager.loadConfiguration(environment)

563

564

val app = embeddedServer(Netty, environment = applicationEnvironment {

565

this.config = config

566

configure(config)

567

developmentMode = config.developmentMode

568

}) {

569

configureApplication()

570

}

571

572

app.start(wait = true)

573

}

574

575

fun Application.configureApplication() {

576

val config = environment.config

577

578

// Validate configuration

579

validateConfiguration()

580

581

// Load type-safe configuration

582

val serverConfig = config.getServerConfig()

583

val dbConfig = config.getDatabaseConfig()

584

585

// Configure application based on config

586

configureDatabase(dbConfig)

587

configureSecurity(config)

588

configureRouting()

589

590

log.info("Application configured successfully")

591

}

592

593

fun Application.configureDatabase(dbConfig: DatabaseConfig) {

594

// Database configuration based on config

595

log.info("Configuring database: ${dbConfig.url}")

596

}

597

598

fun Application.configureSecurity(config: ApplicationConfig) {

599

val securityConfig = config.config("security")

600

601

if (securityConfig.propertyOrNull("jwt.enabled")?.getBoolean() == true) {

602

val jwtSecret = securityConfig.property("jwt.secret").getString()

603

val jwtIssuer = securityConfig.property("jwt.issuer").getString()

604

// Configure JWT

605

log.info("JWT security configured")

606

}

607

608

if (securityConfig.propertyOrNull("cors.enabled")?.getBoolean() == true) {

609

val allowedHosts = securityConfig.property("cors.allowedHosts").getList()

610

// Configure CORS

611

log.info("CORS configured for hosts: $allowedHosts")

612

}

613

}

614

615

// Configuration files structure:

616

/*

617

resources/

618

├── application.conf # Base configuration

619

├── application-development.conf # Development overrides

620

├── application-staging.conf # Staging overrides

621

├── application-production.conf # Production overrides

622

└── logback.xml # Logging configuration

623

624

config/ # External configuration

625

└── application.conf # Local overrides

626

*/

627

```

628

629

This comprehensive configuration documentation covers all aspects of Ktor's configuration system, from basic property access to advanced multi-environment configuration management with validation and type safety.