Engines
The Ktor HTTP client can be used on different platforms, including JVM, Android, JavaScript, and Native. A specific platform may require a specific engine that processes network requests. For example, you can use Apache or Jettyfor JVM applications, OkHttp or Android for Android, Curl for desktop applications targeting Kotlin/Native, and so on. Different engines may have specific features and provide different configuration options.
Requirements and limitations
Supported platforms
The table below lists platforms supported by each engine:
Supported Android/Java versions
Client engines targeting JVM or both JVM and Android support the following Android/Java versions:
Engine  | Android version  | Java version  | 
|---|---|---|
Apache  | 8+  | |
Java  | 11+  | |
Jetty  | 8+  | |
CIO  | 7.0+ *  | 8+  | 
Android  | 1.x+  | 8+  | 
OkHttp  | 5.0+  | 8+  | 
* To use the CIO engine on older Android versions, you need to enable Java 8 API desugaring.
Limitations
The table below shows whether a specific engine supports HTTP/2 and WebSockets:
Engine  | HTTP/2  | WebSockets  | 
|---|---|---|
Apache  | ✅️ (for Apache5)  | ✖️  | 
Java  | ✅  | ✅️  | 
Jetty  | ✅  | ✖️  | 
CIO  | ✖️  | ✅  | 
Android  | ✖️  | ✖️  | 
OkHttp  | ✅  | ✅  | 
Js  | ✅  | ✅  | 
Darwin  | ✅  | ✅  | 
WinHttp  | ✅  | ✅  | 
Curl  | ✅  | ✖️  | 
You also need to consider the following limitations that affect general client configuration and using of specific plugins:
If an engine supports HTTP/2, you can enable it by customizing the engine configuration (see an example for the Java engine).
To configure SSL in the Ktor client, you need to customize the configuration of a selected engine.
Some engines don't support proxy.
The Logging plugin provides different logger types for different platforms.
The HttpTimeout plugin has some limitations for specific engines.
The XML serializer is supported on JVM only.
Add an engine dependency
Apart from the ktor-client-core artifact, the Ktor client requires adding a specific dependency for each engine. For each of the supported platforms, you can see the available engines and required dependencies in a corresponding section:
Create a client with a specified engine
To create the HTTP client with a specific engine, pass an engine class as an argument to the HttpClient constructor. For example, you can create a client with the CIO engine as follows:
Default engine
If you call the HttpClient constructor without an argument, the client will choose an engine automatically depending on the artifacts added in a build script.
This can be useful for multiplatform projects. For example, for a project targeting both Android and iOS, you can add the Android dependency to the androidMain source set and the Darwin dependency to the iosMain source set. The necessary dependency will be selected at compile time.
Configure an engine
You can configure an engine using the engine method. All engines share several common properties exposed by HttpClientEngineConfig, for example:
To learn how to configure a specific engine, see a corresponding section below.
JVM
In this section, we'll take a look at engines available for JVM.
Apache
The Apache engine supports HTTP/1.1 and provides multiple configuration options. You can also use the Apache5 engine if you need HTTP/2 support, which has HTTP/2 enabled by default.
Add the
ktor-client-apache5orktor-client-apachedependency:implementation("io.ktor:ktor-client-apache5:$ktor_version")implementation "io.ktor:ktor-client-apache5:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-apache5-jvm</artifactId> <version>${ktor_version}</version> </dependency>Pass the
Apache5/Apacheclass as an argument to theHttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.apache5.* val client = HttpClient(Apache5)import io.ktor.client.* import io.ktor.client.engine.apache.* val client = HttpClient(Apache)To configure an engine, pass settings exposed by
Apache5EngineConfig/ApacheEngineConfigto theenginemethod:import io.ktor.client.* import io.ktor.client.engine.apache5.* import org.apache.hc.core5.http.* val client = HttpClient(Apache5) { engine { // this: Apache5EngineConfig followRedirects = true socketTimeout = 10_000 connectTimeout = 10_000 connectionRequestTimeout = 20_000 customizeClient { // this: HttpAsyncClientBuilder setProxy(HttpHost("127.0.0.1", 8080)) // ... } customizeRequest { // this: RequestConfig.Builder } } }import io.ktor.client.* import io.ktor.client.engine.apache.* import org.apache.http.HttpHost val client = HttpClient(Apache) { engine { // this: [[[ApacheEngineConfig|https://api.ktor.io/ktor-client/ktor-client-apache/io.ktor.client.engine.apache/-apache-engine-config/index.html]]] followRedirects = true socketTimeout = 10_000 connectTimeout = 10_000 connectionRequestTimeout = 20_000 customizeClient { // this: HttpAsyncClientBuilder setProxy(HttpHost("127.0.0.1", 8080)) setMaxConnTotal(1000) setMaxConnPerRoute(100) // ... } customizeRequest { // this: RequestConfig.Builder } } }
Java
The Java engine uses the Java HTTP Client introduced in Java 11. To use it, follow the steps below:
Add the
ktor-client-javadependency:implementation("io.ktor:ktor-client-java:$ktor_version")implementation "io.ktor:ktor-client-java:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-java-jvm</artifactId> <version>${ktor_version}</version> </dependency>Pass the Java class as an argument to the
HttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.java.* val client = HttpClient(Java)To configure an engine, pass settings exposed by JavaHttpConfig to the
enginemethod:import io.ktor.client.* import io.ktor.client.engine.* import io.ktor.client.engine.java.* val client = HttpClient(Java) { engine { // this: [[[JavaHttpConfig|https://api.ktor.io/ktor-client/ktor-client-java/io.ktor.client.engine.java/-java-http-config/index.html]]] threadsCount = 8 pipelining = true proxy = ProxyBuilder.http("http://proxy-server.com/") protocolVersion = java.net.http.HttpClient.Version.HTTP_2 } }
Jetty
The Jetty engine supports only HTTP/2 and can be configured in the following way:
Add the
ktor-client-jettydependency:implementation("io.ktor:ktor-client-jetty:$ktor_version")implementation "io.ktor:ktor-client-jetty:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-jetty-jvm</artifactId> <version>${ktor_version}</version> </dependency>Pass the Jetty class as an argument to the
HttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.jetty.* val client = HttpClient(Jetty)To configure an engine, pass settings exposed by JettyEngineConfig to the
enginemethod:import io.ktor.client.* import io.ktor.client.engine.jetty.* import org.eclipse.jetty.util.ssl.SslContextFactory val client = HttpClient(Jetty) { engine { // this: [[[JettyEngineConfig|https://api.ktor.io/ktor-client/ktor-client-jetty/io.ktor.client.engine.jetty/-jetty-engine-config/index.html]]] sslContextFactory = SslContextFactory.Client() clientCacheSize = 12 } }
JVM and Android
In this section, we'll take a look at engines available for JVM/Android and their configurations.
Android
The Android engine targets Android and can be configured in the following way:
Add the
ktor-client-androiddependency:implementation("io.ktor:ktor-client-android:$ktor_version")implementation "io.ktor:ktor-client-android:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-android-jvm</artifactId> <version>${ktor_version}</version> </dependency>Pass the Android class as an argument to the
HttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.android.* val client = HttpClient(Android)To configure an engine, pass settings exposed by AndroidEngineConfig to the
enginemethod:import io.ktor.client.* import io.ktor.client.engine.android.* import java.net.Proxy import java.net.InetSocketAddress val client = HttpClient(Android) { engine { // this: [[[AndroidEngineConfig|https://api.ktor.io/ktor-client/ktor-client-android/io.ktor.client.engine.android/-android-engine-config/index.html]]] connectTimeout = 100_000 socketTimeout = 100_000 proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress("localhost", 8080)) } }
OkHttp
The OkHttp engine is based on OkHttp can be configured in the following way:
Add the
ktor-client-okhttpdependency:implementation("io.ktor:ktor-client-okhttp:$ktor_version")implementation "io.ktor:ktor-client-okhttp:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-okhttp-jvm</artifactId> <version>${ktor_version}</version> </dependency>Pass the OkHttp class as an argument to the
HttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.okhttp.* val client = HttpClient(OkHttp)To configure an engine, pass settings exposed by OkHttpConfig to the
enginemethod:import io.ktor.client.* import io.ktor.client.engine.okhttp.* val client = HttpClient(OkHttp) { engine { // this: [[[OkHttpConfig|https://api.ktor.io/ktor-client/ktor-client-okhttp/io.ktor.client.engine.okhttp/-ok-http-config/index.html]]] config { // this: OkHttpClient.Builder followRedirects(true) // ... } addInterceptor(interceptor) addNetworkInterceptor(interceptor) preconfigured = okHttpClientInstance } }
Native
In this section, we'll have a look at how to configure engines targeted for Kotlin/Native.
Darwin
The Darwin engine targets Darwin-based operating systems (such as macOS, iOS, tvOS, and so on) and uses NSURLSession under the hood. To use the Darwin engine, follow the steps below:
Add the
ktor-client-darwindependency:implementation("io.ktor:ktor-client-darwin:$ktor_version")implementation "io.ktor:ktor-client-darwin:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-darwin-macosx64</artifactId> <version>${ktor_version}</version> </dependency>Pass the
Darwinclass as an argument to theHttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.darwin.* val client = HttpClient(Darwin)To configure an engine, pass settings exposed by DarwinClientEngineConfig to the
enginefunction. For instance, you can use theconfigureRequestfunction to accessNSMutableURLRequestorconfigureSessionto customize a session configuration. The code snippet below shows how to useconfigureRequest:val client = HttpClient(Darwin) { engine { configureRequest { setAllowsCellularAccess(true) } } }You can find the full example here: client-engine-darwin.
WinHttp
The WinHttp engine targets Windows-based operating systems. To use the WinHttp engine, follow the steps below:
Add the
ktor-client-winhttpdependency:implementation("io.ktor:ktor-client-winhttp:$ktor_version")implementation "io.ktor:ktor-client-winhttp:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-winhttp-mingwx64</artifactId> <version>${ktor_version}</version> </dependency>Pass the
WinHttpclass as an argument to theHttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.winhttp.* val client = HttpClient(WinHttp)To configure an engine, pass settings exposed by WinHttpClientEngineConfig to the
enginefunction. For instance, you can use theprotocolVersionproperty to change the HTTP version:val client = HttpClient(WinHttp) { engine { protocolVersion = HttpProtocolVersion.HTTP_1_1 } }You can find the full example here: client-engine-winhttp.
Curl
For desktop platforms, Ktor also provides the Curl engine. This engine is supported for the following platforms: linuxX64, macosX64, macosArm64, mingwX64. To use the Curl engine, follow the steps below:
Install the libcurl library.
sudo apt-get install libcurl4-gnutls-devAdd the
ktor-client-curldependency:implementation("io.ktor:ktor-client-curl:$ktor_version")implementation "io.ktor:ktor-client-curl:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-curl-macosx64</artifactId> <version>${ktor_version}</version> </dependency>Pass the
Curlclass as an argument to theHttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.curl.* val client = HttpClient(Curl)To configure an engine, pass settings exposed by
CurlClientEngineConfigto theenginemethod. The code snippet below shows how to disable SSL verification for testing purposes:val client = HttpClient(Curl) { engine { sslVerify = false } }You can find the full example here: client-engine-curl.
JVM, Android, and Native
CIO
CIO is a fully asynchronous coroutine-based engine that can be used on JVM, Android, and Native platforms. It supports only HTTP/1.x for now. To use it, follow the steps below:
Add the
ktor-client-ciodependency:implementation("io.ktor:ktor-client-cio:$ktor_version")implementation "io.ktor:ktor-client-cio:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-cio-jvm</artifactId> <version>${ktor_version}</version> </dependency>Pass the CIO class as an argument to the
HttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.cio.* val client = HttpClient(CIO)To configure an engine, pass settings exposed by CIOEngineConfig to the
enginemethod:import io.ktor.client.* import io.ktor.client.engine.cio.* import io.ktor.network.tls.* val client = HttpClient(CIO) { engine { // this: [[[CIOEngineConfig|https://api.ktor.io/ktor-client/ktor-client-cio/io.ktor.client.engine.cio/-c-i-o-engine-config/index.html]]] maxConnectionsCount = 1000 endpoint { // this: [[[EndpointConfig|https://api.ktor.io/ktor-client/ktor-client-cio/io.ktor.client.engine.cio/-endpoint-config/index.html]]] maxConnectionsPerRoute = 100 pipelineMaxSize = 20 keepAliveTime = 5000 connectTimeout = 5000 connectAttempts = 5 } https { // this: [[[TLSConfigBuilder|https://api.ktor.io/ktor-network/ktor-network-tls/io.ktor.network.tls/-t-l-s-config-builder/index.html]]] serverName = "api.ktor.io" cipherSuites = CIOCipherSuites.SupportedSuites trustManager = myCustomTrustManager random = mySecureRandom addKeyStore(myKeyStore, myKeyStorePassword) } } }
JavaScript
The Js engine can be used for JavaScript projects. This engine uses the fetch API for browser applications and node-fetch for Node.js. To use it, follow the steps below:
Add the
ktor-client-jsdependency:implementation("io.ktor:ktor-client-js:$ktor_version")implementation "io.ktor:ktor-client-js:$ktor_version"<dependency> <groupId>io.ktor</groupId> <artifactId>ktor-client-js</artifactId> <version>${ktor_version}</version> </dependency>Pass the
Jsclass as an argument to theHttpClientconstructor:import io.ktor.client.* import io.ktor.client.engine.js.* val client = HttpClient(Js)You can also call the
JsClientfunction to get theJsengine singleton:import io.ktor.client.engine.js.* val client = JsClient()
You can find the full example here: client-engine-js.
Example: How to configure an engine in a multiplatform mobile project
To configure engine-specific options in a multiplatform mobile project, you can use expect/actual declarations. Let's demonstrate how to achieve this using a project created in the Creating a cross-platform mobile application tutorial:
Open the
shared/src/commonMain/kotlin/com/example/kmmktor/Platform.ktfile and add a top-levelhttpClientfunction, which accepts a client configuration and returnsHttpClient:expect fun httpClient(config: HttpClientConfig<*>.() -> Unit = {}): HttpClientOpen
shared/src/androidMain/kotlin/com/example/kmmktor/Platform.ktand add an actual declaration of thehttpClientfunction for the Android module:import io.ktor.client.* import io.ktor.client.engine.okhttp.* import java.util.concurrent.TimeUnit actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(OkHttp) { config(this) engine { config { retryOnConnectionFailure(true) connectTimeout(0, TimeUnit.SECONDS) } } }This example shows how to configure the OkHttp engine, but you can also use other engines supported for Android.
Open
shared/src/iosMain/kotlin/com/example/kmmktor/Platform.ktand add an actual declaration of thehttpClientfunction for the iOS module:import io.ktor.client.* import io.ktor.client.engine.darwin.* actual fun httpClient(config: HttpClientConfig<*>.() -> Unit) = HttpClient(Darwin) { config(this) engine { configureRequest { setAllowsCellularAccess(true) } } }Finally, open
shared/src/commonMain/kotlin/com/example/kmmktor/Greeting.ktand replace theHttpClient()constructor with thehttpClientfunction call:private val client = httpClient()