Scripting with Kotlin
Kotlin is a modern and versatile programming language that is used for many targets and types of applications.
Although it is a compiled language at its core, Kotlin supports scripting, which enables small programs or scripts to be written and executed directly, providing a developer experience (DX) similar to other scripting languages. In this article, three ways of scripting with Kotlin are presented: using the *.main.kts
file, using kscript, and using JBang. Kotlin notebooks are also mentioned as a bonus at the end.
Scripting with *.main.kts
The official way to write Kotlin scripts is with a *.main.kts
file, which is a special file that can be executed directly. Such a file may contain Kotlin code and can be run using the kotlin
command. For example, a script.main.kts
file may be created with the following content:
The script can be executed using the following command:
This prints "Hello, Kotlin scripting!" to the console. The script can also be made executable by running:
and then run it directly:
*.main.kts
scripts provide features such as debugging, implicit argv
(command line arguments), and dependencies via @file:DependsOn
and @file:Repository
.
Caching support for fast execution is also available by default.
Below is an example of a script that prints the last 10 posts from a given RSS feed URL.
This example demonstrates the use of the @file:DependsOn
annotation to include dependencies, and the use of the argv
variable to obtain command line arguments.
#!/usr/bin/env kotlin
@file:DependsOn("com.apptasticsoftware:rssreader:3.9.3")
import com.apptasticsoftware.rssreader.RssReader
import kotlin.jvm.optionals.getOrDefault
val feedUrl = args[0]
println("Showing the last 10 posts from $feedUrl")
var rssReader = RssReader()
var items = rssReader.read(feedUrl).filter { it.title.isPresent }
.map { it.title.getOrDefault("") }.toList().take(10)
println(items.joinToString(separator = "\n- ", prefix = "- "))
The script can be executed with the following command:
kotlin rssreader.main.kts [feed URL]
# For example:
rssreader.main.kts "https://blog.worldline.tech/index.xml"
The output of the script is similar to the following:
Showing the last 10 posts from https://blog.worldline.tech/index.xml
- The Yoga of Image Generation – Part 3
- Insights from Onboarding young developers and Mentoring Experiences
- The Yoga of Image Generation – Part 2
- The Superpowers of JavaScript Proxies
- Devops on Google Cloud Platform: Automating your build delivery on GCP in nutshell
- Introduction to QEMU 386
- The Yoga of Image Generation – Part 1
- Proper key management in the cloud with a Cloud Secure Module
- The OAuth proxification guide for frontend developers with Microsoft EntraID
- Gemini, but the other one
Kotlin scripting with *.main.kts
files is a straightforward way to write and execute Kotlin scripts.
This approach is available out of the box with the Kotlin compiler.
However, several limitations have been observed:
First, the *.main.kts
file is currently only supported by IntelliJ IDEA, and a restart of the IDE may be required for dependencies to be recognized.
Second, scripts may not run with the ./script.main.kts
command due to the error env: kotlin\r: No such file or directory
, which prevents execution. In such cases, the kotlin script.main.kts
command must be used instead.
Lastly, the status of this feature is still experimental, so changes may occur in the future.
For further information, JetBrains has published a blog post about the current state of Kotlin scripting by the end of 2024, which initially led to some doubts and misunderstandings about the future of official Kotlin scripting support. Ultimately, the feedback was related to other less successful and relevant scripting features being dropped.
Additional perspectives on the current state of official Kotlin scripting can be found in InfoWorld and Martin Bonin posts.
In addition to the official *.main.kts
scripting, there are two other popular ways to write Kotlin scripts: using kscript and JBang.
Scripting with kscript
kscript is an open-source tool designed to provide a user-friendly experience for writing Kotlin scripts. It offers a command-line interface and features that simplify the process of writing and running Kotlin scripts.
After installing kscript, a script file with the .kts
extension can be created, and the shebang line added at the top of the file.
For example, the following file, named script.kts
, is a kscript file that prints "Hello, Kotlin scripting!" and takes a command line argument:
As with *.main.kts
scripting, the script can be run using the kscript
command:
The script can also be made executable by running:
and then run it directly:
kscript provides features similar to the official *.main.kts
scripting, such as dependency management and command line arguments.
Additional developer-friendly features are also available, such as passing code from the command line.
The following commands demonstrate two examples of passing code from the command line to kscript:
kscript was widely used in the past, when the official Kotlin scripting support was still in its early stages.
However, many exclusive features of kscript have since been integrated into the official *.main.kts
scripting, such as dependency management, command line arguments, and more.
Additionally, kscript has not been updated for a long time, with the last release in July 2023.
A more feature-rich third-party Kotlin scripting experience can be achieved with JBang, as described in the next section.
Scripting with JBang
JBang is a multipurpose tool centered around using self-contained files for JVM languages (Java, Kotlin, etc.). In addition to scripting, jars can be generated, executed, and scripts can be shared in a streamlined way. For more details on JBang features aside from scripting, see the blog post about JBang, a talk at Devoxx UK, and the official website. This section focuses on the scripting features of JBang.
The following commands showcase how to use JBang to create and run a Kotlin script:
jbang init -t hello.kt hello-jbang.kt
# Execute the file
jbang hello-jbang.kt
# or like this
chmod +x hello-jbang.kt
./hello-jbang.kt
The hello-jbang.kt
file is a regular Kotlin file with a main method. It is considered a script due to the JBang annotation at the top of the file, also called a shebang, which instructs JBang to execute the file as a script.
The content of the file is as follows:
JBang supports all scripting features of *.main.kts
with these additions:
- File extension is .kt: the same extension as regular Kotlin files. Thus, the file must have a main method.
- Templates: the ability to create scripts from predefined models.
- Include other sources: useful for sharing code between scripts.
- Include resources: if the code has resources, such as an app icon or a translation file.
- Compiler and runtime options: for customizing the behavior of the compiler and the runtime.
The following script demonstrates a Quarkus REST server written in Kotlin using JBang.
It uses the //DEPS
feature to include dependencies.
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS io.ktor:ktor-bom:3.0.1@pom
//DEPS io.ktor:ktor-server-netty-jvm
//DEPS io.ktor:ktor-serialization-jackson-jvm
//DEPS io.ktor:ktor-server-content-negotiation-jvm
import com.fasterxml.jackson.databind.SerializationFeature
import io.ktor.serialization.jackson.*
import io.ktor.server.application.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*
import io.ktor.server.plugins.contentnegotiation.*
import io.ktor.server.response.*
import io.ktor.server.routing.*
data class Todo(val title: String, val isCompleted: Boolean)
fun main(args: Array<String>) {
val todos = listOf(Todo("Sleep", false), Todo("Eat", true))
print(todos)
embeddedServer(Netty, 8080) {
install(ContentNegotiation) {
jackson {
enable(SerializationFeature.INDENT_OUTPUT)
}
}
routing { get("/") { call.respond(todos) } }
}.start(wait = true)
}
It can be run with the following command, which downloads the script and runs it locally:
JBang provides a versatile and feature-rich approach to writing Kotlin scripts.
The next section covers an alternative way of running Kotlin code blocks, which is not exactly scripting but is noteworthy.
Bonus: Kotlin notebooks
Jupyter Notebook is a standard format for writing markdown, code, and the result of the code, all in a single file.
The extension of these files is .ipynb
(interactive Python notebooks).
Notebooks are widely used for the following reasons:
- The language of code blocks can be any language, as long as a Jupyter Kernel for that language is installed.
- Code blocks can be executed in any order and independently, and there is a global session context that retains the values of global variables across code block executions. Even though there is Python in the extension name, it does not indicate that only Python is supported.
- Code and markdown blocks can be written in any order.
- GitHub, GitLab, and many other tools and apps render Jupyter Notebooks properly, including syntax highlighting and graphics and charts generated by code.
These features make Jupyter Notebooks suitable for writing documentation, experimenting, data science, and scripting.
Kotlin has official scripting support through the availability of a Kotlin Kernel, which allows Kotlin code blocks to be run, and IntelliJ and VSCode extensions for Kotlin notebooks, which enable editing features found in regular Kotlin files (syntax highlighting, code suggestions, etc.).
The following screenshot shows a Kotlin notebook with a markdown block, a code block, and the result of the code block.
The notebook can be opened and edited with IntelliJ IDEA, VSCode, or any other Jupyter Notebook-compatible editor. It can also be rendered on GitHub or GitLab. The above notebook can be viewed on GitHub at this link.
Other screenshots of Kotlin notebooks are shown below:
(source gaplo917/awesome-kotlin-notebook)
Kotlin notebooks provide an interactive and visual way to write Kotlin code. They are not exactly scripting, but can be used for scripting-like tasks, such as experimenting with code, writing documentation, and sharing code snippets.
Conclusion
Kotlin is a powerful and versatile language.
This post has explored three ways to write scripts with Kotlin: using the official *.main.kts
scripting, using kscript, and using JBang.
JBang and the official approach each have their own advantages. kscript is less recommended due to its lack of features and updates.