Since its earliest release, Java has touted itself as a " " programming language; the idea was that a programmer could develop an app in Java, have it compiled down to bytecode, and become an executable that can run on any platform, regardless of operating system or platform. It was able to do so in part by a runtime known as the Java Virtual Machine, or . write once, run everywhere JVM To Java's credit, the JVM was (and still is!) an incredibly fine-tuned runtime that abstracted away a computer's underlying hardware. While Java as a programming language survives to this day, it is often viewed as cumbersome, stodgy, and representative of an outdated approach to implementing solutions. In the last 10 years, more and more languages that run on the JVM have been developed but, they look and feel nothing like Java. One such language is . Because of the JVM, it has no real performance advantages over regular Java. Still, its strength lies in the fact that it prioritizes legibility in a way that Java does not. Consider, for example, printing a substring in Java: Kotlin // Java String input = "What is the answer to the Ultimate Question of Life, the Universe, and Everything? 42"; String answer = input.substring(input.indexOf("?") + 1); System.out.println(answer); You must first get the index of the character you want to be in the substring, add one (since strings are zero-indexed), and call to write to stdout. System.out.println In Kotlin, this is much shorter: // Kotlin val input = "What is the answer to the Ultimate Question of Life, the Universe, and Everything? 42" val answer = input.substringAfter("?") println(answer) Kotlin has garnered so much interest that . Google even recommends it over Java for developing Android apps In this post, we'll take a quick look at how to develop an app in Kotlin. We'll build a simple API with a PostgreSQL database and deploy it to Heroku to see it live. Prerequisites Before we begin, you'll need to make sure you've got the following software installed on your machine: . This is completely free and doesn't require any payment information. An account on Heroku . Once your application is on Heroku, this will make managing it much easier. The Heroku CLI You'll need to have installed (>= 1.4). Kotlin You'll also need installed (>= 7.0). Gradle You will also need to be a little familiar with and have it installed on your machine. Git We’re going to be using IDE for this Kotlin app. Their documentation provides some guidance on how to create a new project. Make sure you select the following options: the IntelliJ We want to create a Kotlin application that uses Gradle as a build system Set the name of the project to kotlin-api Set the JDK version to 16. If you don’t have this version installed, you can select … from the dropdown, then choose version 16 Download JDK Oracle Open JDK After the IDE sets everything up, you should have a directory structure that looks roughly like this: kotlin-api ├── build.gradle.kts └── src ├── main │ ├── kotlin Our Kotlin files will be kept in And our build logic will be in . src/main/kotlin build.gradle.kts Getting started Gradle is a build tool for a variety of languages. It also acts as a dependency management tool, similar to Maven. You’ll already have some lines in your file, which the IDE automatically added to be helpful. You can delete all of that and paste in these lines instead: build.gradle.kts plugins { id("java") id("org.jetbrains.kotlin.jvm") version "1.5.10" id("org.springframework.boot") version "2.4.3" id("io.spring.dependency-management") version "1.0.11.RELEASE" } group "com.example" version "0.0.1" repositories { mavenCentral() } dependencies { implementation("org.jetbrains.kotlin:kotlin-stdlib") implementation("org.springframework.boot:spring-boot-starter-web") implementation("org.springframework.boot:spring-boot-starter") developmentOnly("org.springframework.boot:spring-boot-devtools") } These lines specify our project's dependencies and where to find them. For example, we want to use at version 2.4.3, which is why it's defined within the block. We point out the repositories where the packages can be found—at — and which exposed classes we want to use ( ). org.springframework.boot plugins mavenCentral() implementation( "org.springframework.boot:spring-boot-starter-web") Let's create two small files to test our setup. Create a file called in the folder and paste in the following: Application.kt src/main/kotlin package com.example import org.springframework.boot.SpringApplication import org.springframework.boot.autoconfigure.SpringBootApplication @SpringBootApplication open class Application fun main(args: Array<String>) { SpringApplication.run(Application::class.java, *args) } This starts a default app using the Spring framework. The real magic happens in this next file, , which you should create alongside in : Controller.kt Application.kt src/main/kotlin package com.example import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RestController @RestController class GreetingController { @GetMapping("/{name}") fun get(@PathVariable name: String) = "Hello, $name" } Here, we define a route ( ), where is a dynamic value. By placing this decorator over a Kotlin method ( , or "a function named get"), we're able to match the route to whatever behavior we want—in this case, returning a greeting with the path name for a request. @GetMapping("/{name}") {name} fun get GET In order for the IDE to know how to launch our application, we need to create . At the top of the IDE menu, click the button that says . Then, select . Next, choose Gradle from the list. For the Gradle project name, enter kotlin-api. In the Tasks field, type . is a Gradle task provided by the Spring framework, which will compile our code and start the server. a run configuration Add Configuration Add new run configuration bootRun bootRun Click . Ok You should now have a green Play button in your IDE menu bar. When you click on this, the IDE will execute to build this Kotlin app and start the server. When that finishes, navigate to . You should see a nice greeting. gradle bootRun http://localhost:8080/world Interacting with the database Now, let's get to the (somewhat) serious stuff. Suppose we wanted to attach a database to this project. In a Maven/Java world, we'd need to update an XML file and add a reference to a JAR file. In Gradle, we can get by with just adding a few lines to our file: build.gradle.kts dependencies { # ... implementation("com.zaxxer:HikariCP:4.0.3") runtimeOnly("org.postgresql:postgresql") # ... } Here, we've included in our project, which is a popular database connection driver. We also indicate that we want to "load" the library during runtime. With just these two lines, we've let our configuration know that we want to interact with a PostgreSQL database. If you already have a PostgreSQL database running locally, that's great. You'll be able to continue the rest of this guide locally and see the results when browsing localhost. If you don't have PostgreSQL, don't fret — we'll show you just how easy it is to deploy this app on Heroku, which will take care of the infrastructure for you. HikariCP org.postgresql Head back to and replace it with the contents below. This takes some of what we had from before but adds to it. We'll go over the changes shortly. Controller.kt package com.example import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RestController import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.http.MediaType import com.zaxxer.hikari.HikariConfig import com.zaxxer.hikari.HikariDataSource import java.net.URI import javax.sql.DataSource @RestController class GreetingController { val dataSource = dataSource() val connection = dataSource.connection @GetMapping("/{name}") fun get(@PathVariable name: String) = "Hello, $name" @PostMapping(value = ["/add-name"], consumes = [MediaType.TEXT_PLAIN_VALUE]) fun post(@RequestBody requestBody: String) : String { initDb() val stmt = connection.createStatement() stmt.executeUpdate("INSERT INTO names values('$requestBody')") return "Added $requestBody" } @GetMapping("/everyone") fun getAll() : String { initDb() val stmt = connection.createStatement() val rs = stmt.executeQuery("SELECT name FROM names") val output = ArrayList<String>() while (rs.next()) { output.add(rs.getString("name")) } val names = output.joinToString(", ") return "Here are the names: $names" } internal fun initDb() { val stmt = connection.createStatement() stmt.executeUpdate("CREATE TABLE IF NOT EXISTS names (name text)") } internal fun dataSource(): HikariDataSource { val config = HikariConfig() var dbUri = URI(System.getenv("DATABASE_URL") ?: "postgresql://localhost:5432/") var dbUserInfo = dbUri.getUserInfo() var username: String?; var password: String?; if (dbUserInfo != null) { username = dbUserInfo.split(":").get(0) password = dbUserInfo.split(":").get(1) } else { username = System.getenv("DATABASE_USERNAME") ?: null password = System.getenv("DATABASE_PASSWORD") ?: null } if (username != null) { config.setUsername(username) } if (password != null) { config.setPassword(password) } val dbUrl = "jdbc:postgresql://${dbUri.getHost()}:${dbUri.getPort()}${dbUri.getPath()}" config.setJdbcUrl(dbUrl) return HikariDataSource(config) } } There's quite a lot going on here! Let's start from the bottom. We define a function called which provides a connection to our database. Because we're building , our database credentials are stored in an environment variable called . We fetch that URL and pull out the username and password from it if one exists. If not, we check another two environment variables for that information — and . We then put all that information together into a format that the database connector needs. The function creates a table called , with a single text column called . The endpoint has a decorator just like before. This defines a route, which gets all the names from the database. dataSource a 12-Factor app DATABASE_URL DATABASE_USERNAME DATABASE_PASSWORD initDb names name /everyone @GetMapping GET /everyone Finally, we've added something rather new: a decorator. Here, we need to define what types of content this route can accept. In this case, it a media type (in other words, ). Whatever string of information we put in the request body will be added to the database. In just a few lines, we've built a small API that we can add to and query. @PostMapping POST consumes TEXT_PLAIN_VALUE "Content-Type: text/plain" If you start this server now—and if you have PostgreSQL running locally — you should be able to interact with it. Try making the following request: $ curl -H "Content-Type: text/plain" -X POST http://localhost:8080/add-name -d 'Frank' If you navigate to , you'll see that was included. http://localhost:8080/everyone Frank Deploying to Heroku It's time to see just how easy it is to get Kotlin running on Heroku. First, we need to create a file that's specific to Heroku: . This text file defines how our application should boot and run. the Procfile Create a file named in the root level directory, right next to your file. Copy-paste the following lines into it: Procfile build.gradle.kts web: java -jar build/libs/kotlin-api.jar --server.port=$PORT Here, we're saying that we want Heroku to run . That JAR is packaged and built during the deployment process; Heroku will create it automatically for us because it knows how to execute the Gradle task to do so. We are also binding the environment variable so that Heroku knows which port the server is listening to. java -jar build/libs/kotlin-api.jar $PORT Next, run the following Git commands: $ git init $ git add . $ git commit -m "Preparing my first Kotlin app" Since we have the Heroku CLI installed, we can : call heroku create on the command line to generate an app $ heroku create Creating app... done, ⬢ desolate-plains-67007 Created http://desolate-plains-67007.herokuapp.com/ | git@heroku.com:desolate-plains-67007.git Your app will be assigned a random name — in this example, it's — as well as a publicly accessible URL. desolate-plains-67007 In order to provision a database, we use the command. Calling it without arguments will let us know if any exist: heroku addons $ heroku addons No add-ons for app desolate-plains-67007. No add-ons exist for our app, which makes sense — we just created it! To add a PostgreSQL database, we can use the command like this: addons:create $ heroku addons:create heroku-postgresql:hobby-dev Heroku offers several tiers of PostgreSQL databases. is the free tier, so we can play around with this without paying a dime. hobby-dev Your code is ready; your Heroku app is configured — you’re ready to deploy. This is the easy part! Just type out the following command: $ git push heroku master Your code will be pushed to Heroku. From that point on, Heroku will take over. You'll see your build logs scrolling through your terminal. This will show you what Heroku is installing on your behalf and where you are in the build process. After it’s complete, you can visit your special URL in the browser (in this case, ) and interact with the API on the internet! https://desolate-plains-67007.herokuapp.com Learning more Kotlin's — combined with the ease of Gradle — make it ideal for enterprises that need to rely on battle-tested Java packages. Because of its interoperability with Java, Kotlin is ideal as a transitional language; vast swaths of Java code can be converted into Kotlin while still maintaining a functional app. Deploying to Heroku is smooth, and I didn't even take advantage of the different ways to fine-tune Java and JVM-based apps for deployment. performant design and legible syntax