Computer scienceBackendKtorKtor Advanced

Deploying Ktor App (using ShadowJar plugin)

14 minutes read

You already know how to create the simplest Ktor application and access its routes in the browser. Today, we will learn how to deploy our application on any server that supports Java.

Deployment

We have a simple Ktor application. It runs on port 8080 and displays "Hello Ktor!" when accessing the "/" address.

Application.kt:

package com.example

import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.response.*
import io.ktor.server.routing.*

fun main() {
    embeddedServer(Netty, port = 8080, host = "0.0.0.0", module = Application::module)
        .start(wait = true)
}

fun Application.module() {
    routing {
        get("/") {
            call.respondText("Hello Ktor!")
        }
    }
}

To run and test your application, you can click "Run Application.kt" in IntelliJ IDEA:

Starting Application.kt file

IDE Console

In a browser, you can go to localhost:8080 and see that the application is running:

Checking the application in the Browser

This way of launching an application is convenient for development.

But how to launch an application on a real server so that other users can use it? To do this, we need to package the application into a JAR file and run it on a server with Java installed.

Creating JAR with Gradle Shadow plugin

To create the JAR file, we use the Gradle Shadow plugin.

First, let's add it to build.gradle.kts in the plugins section:

plugins {
    id("com.github.johnrengelman.shadow") version "7.0.0"
}

Next, add the shadowJar task to the tasks section. If you don't have a tasks section in build.gradle.kts, add this section at the end of the file:

tasks{
    shadowJar {
        manifest {
            attributes(Pair("Main-Class", "com.example.ApplicationKt"))
        }
    }
}

Here we have specified the main class of our application.

We have the following build.gradle.kts:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

val ktor_version: String by project
val kotlin_version: String by project
val logback_version: String by project

plugins {
    kotlin("jvm") version "1.7.0"
    id("io.ktor.plugin") version "2.3.2"
    id("com.github.johnrengelman.shadow") version "7.0.0"
}

group = "com.example"
version = "0.0.1"
application {
    mainClass.set("com.example.ApplicationKt")

    val isDevelopment: Boolean = project.ext.has("development")
    applicationDefaultJvmArgs = listOf("-Dio.ktor.development=$isDevelopment")
}

repositories {
    mavenCentral()
}

dependencies {
    implementation("io.ktor:ktor-server-core-jvm:$ktor_version")
    implementation("io.ktor:ktor-server-netty-jvm:$ktor_version")
    implementation("ch.qos.logback:logback-classic:$logback_version")
    testImplementation("io.ktor:ktor-server-tests-jvm:$ktor_version")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version")
    implementation(kotlin("stdlib-jdk8"))
}
val compileKotlin: KotlinCompile by tasks
compileKotlin.kotlinOptions {
    jvmTarget = "1.8"
}
val compileTestKotlin: KotlinCompile by tasks
compileTestKotlin.kotlinOptions {
    jvmTarget = "1.8"
}

tasks{
    shadowJar {
        manifest {
            attributes(Pair("Main-Class", "com.example.ApplicationKt"))
        }
    }
}

Next, apply the build.gradle.kts updates by clicking the corresponding popup button in the upper right part of the IDE:

Gradle rebuild button

Now we can easily run the created shadowJar task through the terminal.

Go to the root folder of your project and run the appropriate command:

On Windows:

gradlew.bat shadowJar

On Linux/Mac:

./gradlew shadowJar

After running the command, if you have done everything correctly, you will see "BUILD SUCCESSFUL":

Executing the shadowJar command in the console

Now, if we go to the build/libs folder, we can see our created JAR file:

Obtained jar file in explorer

This way of packaging an application is called Fat JAR because the resulting JAR file contains all the necessary dependencies and is ready to run. Therefore, this method is very convenient.

Creating JAR with Ktor Gradle plugin

In new versions of Ktor, there is a new and more convenient way to create a JAR file using the Ktor Gradle plugin.

By default, this plugin is usually specified in build.gradle.kts, so there is no need for you to manually specify command line tasks for it.

Make sure you have this plugin connected and the main application class configured:

plugins {
    id("io.ktor.plugin") version "2.3.2"
}
application {
    mainClass.set("com.example.ApplicationKt")
}

These lines were already present by default in our previously provided build.gradle.kts file.

The Ktor plugin provides the buildFatJar task, and doesn't need to be manually specified. It can run in the same way as shadowJar:

On Windows:

gradlew.bat buildFatJar

On Linux/Mac:

./gradlew buildFatJar

After running the command, if you have done everything correctly, you will see "BUILD SUCCESSFUL":

Executing the buildFatJar command in the console

You can also find the resulting JAR in the build/libs folder.

Running Gradle tasks through the IDE interface

If you are using IntelliJ IDEA, you can run Gradle tasks more conveniently. In the upper right part of the IDE window, there is a special "Gradle" tab, which is intended for managing dependencies and launching tasks via UI.

Running Gradle tasks via IDE

Running Gradle tasks via IDE

In the "Tasks" drop-down list, you can see all of Gradle's available tasks, including the shadowJar and buildFatJar tasks we discussed earlier.

If you double-click on one of these tasks, the console will open, and the task will be executed.

Running Gradle tasks via IDE

After that, the finished JAR will be in the build/libs folder.

Running a JAR file

Once our application's JAR file is ready, all we have to do is run it.

To do this, go to the folder with the JAR file and run it using the standard Java command: java -jar <file name>

java -jar ktor-sample-all.jar

After that, our application will start in the terminal:

Running a jar file in the terminal

In a browser, you can go to localhost:8080, and see that the application is running:

Checking the application in the Browser

We can close the IDE at this point. The application will work until we close the terminal where our JAR file is running.

This way, our application can run on any server that has Java. All you need is to run the JAR file with your application. If our computer had a static IP address and a proper firewall setting, the application could be accessed from the Internet via a link like http://<your computer's ip>:8080/. Later you can buy a domain name and link it to the server's IP address to refer to the site through the name instead of the IP.

To ease the process of setting up such a server, there are ready-made hosting solutions that simplify the deployment process. For example, Heroku. You can read the official tutorial on how to host a Ktor application on Heroku.

Conclusion

In this topic, we learned about deploying a Ktor application.

We've learned:

  • The reason why you need to create a JAR file.
  • How to create a JAR file with the Gradle Shadow plugin.
  • How to create a JAR file with the Ktor Gradle plugin.
  • How to run Gradle tasks through the IntelliJ IDEA interface.
  • How to run the resulting JAR file on a Java-enabled server.

Now let's put what we've learned into practice.

How did you like the theory?
Report a typo