Ktor 3.2.1 Help

Modules

Ktor allows you to use modules to structure your application by defining a specific set of routes inside a specific module. A module is an extension function of the Application class. In the example below, the module1 extension function defines a module that accepts GET requests made to the /module1 URL path.

import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* fun Application.module1() { routing { get("/module1") { call.respondText("Hello from 'module1'!") } } }

Loading modules in your application depends on the way used to create a server: in code using the embeddedServer function or by using the application.conf configuration file.

embeddedServer

Typically, the embeddedServer function accepts a module implicitly as a lambda argument. You can see the example in the Configuration in code section. You can also extract application logic into a separate module and pass a reference to this module as the module parameter:

package com.example import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* import io.ktor.server.engine.* import io.ktor.server.netty.* fun main() { embeddedServer(Netty, port = 8080, module = Application::module).start(wait = true) } fun Application.module() { module1() module2() } fun Application.module1() { routing { get("/module1") { call.respondText("Hello from 'module1'!") } } } fun Application.module2() { routing { get("/module2") { call.respondText("Hello from 'module2'!") } } }

You can find the full example here: embedded-server-modules.

Configuration file

If you use the application.conf or application.yaml file to configure a server, you need to specify modules to load using the ktor.application.modules property.

Suppose you have three modules defined in two packages: two modules in the com.example package and one in the org.sample package.

package com.example import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args) fun Application.module1() { routing { get("/module1") { call.respondText("Hello from 'module1'!") } } } fun Application.module2() { routing { get("/module2") { call.respondText("Hello from 'module2'!") } } }
package org.sample import io.ktor.server.application.* import io.ktor.server.response.* import io.ktor.server.routing.* fun Application.module3() { routing { get("/module3") { call.respondText("Hello from 'module3'!") } } }

To reference these modules in a configuration file, you need to provide their fully qualified names. A fully qualified module name includes a fully qualified name of the class and an extension function name.

ktor { application { modules = [ com.example.ApplicationKt.module1, com.example.ApplicationKt.module2, org.sample.SampleKt.module3 ] } }
ktor: application: modules: - com.example.ApplicationKt.module1 - com.example.ApplicationKt.module2 - org.sample.SampleKt.module3

You can find the full example here: engine-main-modules.

Concurrent module loading

You can use suspendable functions when creating application modules. They allow events to run asynchronously when starting the application. To do that, add the suspend keyword:

suspend fun Application.installEvents() { val kubernetesConnection = connect(property<KubernetesConfig>("app.events")) }

You can also launch all application modules independently, so when one is suspended, the others are not blocked. This allows for non-sequential loading for dependency injection and, in some cases, faster loading.

Configuration options

The following Gradle configuration properties are available:

Property

Type

Description

Default

ktor.application.startup

sequential/concurrent

Defines how application modules are loaded

sequential

ktor.application.startupTimeoutMillis

Long

Timeout for application module loading (in milliseconds)

100000

Enable concurrent module loading

To opt into concurrent module loading, add the following property to your gradle.properties file:

ktor.application.startup = concurrent

For dependency injection, you can load the following modules in order of appearance without issues:

suspend fun Application.installEvents() { // Suspends until provided val kubernetesConnection = dependencies.resolve<KubernetesConnection>() } suspend fun Application.loadEventsConnection() { dependencies.provide<KubernetesConnection> { connect(property<KubernetesConfig>("app.events")) } }
07 July 2025