Getting Started on Heroku with Kotlin
Introduction
This tutorial will have you deploying a Kotlin app in minutes.
Hang on to learn how it all works, so you can make the most out of Heroku.
The tutorial assumes that you have:
- a free Heroku account
- Java 8 installed
We recommend using our low-cost plans to complete this tutorial. Eligible students can apply for platform credits through our new Heroku for GitHub Students program.
Set up
The Heroku CLI requires Git, the popular version control system. If you don’t already have Git installed, complete the following before proceeding:
In this step you’ll install the Heroku Command Line Interface (CLI). You use the CLI to manage and scale your applications, provision add-ons, view your application logs, and run your application locally.
Download and run the installer for your platform:
Download the appropriate installer for your Windows installation:
Run the following from your terminal:
$ sudo snap install heroku --classic
Once installed, you can use the heroku
command from your command shell.
Use the heroku login
command to log in to the Heroku CLI:
$ heroku login
heroku: Press any key to open up the browser to login or q to exit
› Warning: If browser does not open, visit
› https://cli-auth.heroku.com/auth/browser/***
heroku: Waiting for login...
Logging in... done
Logged in as me@example.com
This command opens your web browser to the Heroku login page. If your browser is already logged in to Heroku, simply click the Log in
button displayed on the page.
This authentication is required for both the heroku
and git
commands to work correctly.
If you’re behind a firewall that requires use of a proxy to connect with external HTTP/HTTPS services, you can set the HTTP_PROXY
or HTTPS_PROXY
environment variables in your local development environment before running the heroku
command.
Prepare the app
In this step, you will prepare a simple application that can be deployed.
To clone the sample application so that you have a local version of the code that you can then deploy to Heroku, execute the following commands in your local command shell or terminal:
$ git clone https://github.com/heroku/kotlin-getting-started.git
$ cd kotlin-getting-started
You now have a functioning Git repository that contains a simple application as well as a build.gradle
file, which is used by the Gradle dependency manager.
Deploy the app
In this step you will deploy the app to Heroku.
Create an app on Heroku, which prepares Heroku to receive your source code:
$ heroku create
Creating young-spire-55658... done, ⬢ young-spire-55658
http://young-spire-55658.herokuapp.com/ | https://git.heroku.com/young-spire-55658.git
Git remote heroku added
When you create an app, a git remote (called heroku
) is also created and associated with your local git repository.
Heroku generates a random name (in this case young-spire-55658
) for your app, or you can pass a parameter to specify your own app name.
Now deploy your code:
$ git push heroku master
Initializing repository, done.
Counting objects: 68, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (19/19), done.
Writing objects: 100% (68/68), 7.07 KiB | 0 bytes/s, done.
Total 68 (delta 22), reused 65 (delta 22)
remote: -----> Gradle app detected
remote: -----> Spring Boot detected
remote: -----> Installing OpenJDK 1.8... done
remote: -----> Building Gradle app...
remote: -----> executing ./gradlew build -x test
...
remote: BUILD SUCCESSFUL
remote:
remote: Total time: 56.003 secs
remote: -----> Discovering process types
remote: Procfile declares types -> (none)
remote: Default types for buildpack -> web
remote:
remote: -----> Compressing...
remote: Done: 101.2M
remote: -----> Launching...
remote: Released v3
remote: https://young-spire-55658.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/young-spire-55658.git
* [new branch] master -> master
The application is now deployed. Ensure that at least one instance of the app is running:
$ heroku ps:scale web=1
Now visit the app at the URL generated by its app name. As a handy shortcut, you can open the website as follows:
$ heroku open
View logs
Heroku treats logs as streams of time-ordered events aggregated from the output streams of all your app and Heroku components, providing a single channel for all of the events.
View information about your running app using one of the logging commands, heroku logs --tail
:
$ heroku logs --tail
2017-06-13T19:42:30.937420+00:00 app[web.1]: _ _ _
2017-06-13T19:42:30.937429+00:00 app[web.1]: | | | | | |
2017-06-13T19:42:30.937430+00:00 app[web.1]: | |__| | ___ _ __ ___ | | ___ _
2017-06-13T19:42:30.937430+00:00 app[web.1]: | __ |/ _ \ '__/ _ \| |/ / | | |
2017-06-13T19:42:30.937431+00:00 app[web.1]: | | | | __/ | | (_) | <| |_| |
2017-06-13T19:42:30.937432+00:00 app[web.1]: |_| |_|\___|_| \___/|_|\_\\__,_|
2017-06-13T19:42:30.937433+00:00 app[web.1]:
2017-06-13T19:42:30.937433+00:00 app[web.1]: :: Built with Spring Boot :: 1.5.3.RELEASE
2017-06-13T19:42:30.937462+00:00 app[web.1]:
...
2017-06-13T19:42:47.268525+00:00 app[web.1]: 2017-06-13 19:42:47.268 INFO 4 --- [ main] com.example.Application$Companion : Started Application.Companion in 17.
773 seconds (JVM running for 19.622)
2017-06-13T19:42:47.542769+00:00 heroku[web.1]: State changed from starting to up
Visit your application in the browser again, and you’ll see another log message generated.
Press Control+C
to stop streaming the logs.
Define a Procfile
Use a Procfile, a text file in the root directory of your application, to explicitly declare what command should be executed to start your app.
The Procfile
in the example app you deployed looks like this:
web: java -jar build/libs/kotlin-getting-started-1.0.jar
This declares a single process type, web
, and the command needed to run it. The name web
is important here. It declares that this process type will be attached to the HTTP routing stack of Heroku, and receive web traffic when deployed.
Procfiles can contain additional process types. For example, you might declare one for a background worker process that processes items off of a queue.
Scale the app
Right now, your app is running on a single web dyno. Think of a dyno as a lightweight container that runs the command specified in the Procfile
.
You can check how many dynos are running using the ps
command:
$ heroku ps
=== web (Free): java -jar build/libs/kotlin-getting-started-1.0.jar (1)
web.1: up 2016/07/07 09:06:41 +0100 (~ 4m ago)
By default, your app is deployed on a free dyno. Free dynos will sleep after a half hour of inactivity (if they don’t receive any traffic). This causes a delay of a few seconds for the first request upon waking. Subsequent requests will perform normally. Free dynos also consume from a monthly, account-level quota of free dyno hours - as long as the quota is not exhausted, all free apps can continue to run.
To avoid dyno sleeping, you can upgrade to a hobby or professional dyno type as described in the Dyno Types article. For example, if you migrate your app to a professional dyno, you can easily scale it by running a command telling Heroku to execute a specific number of dynos, each running your web process type.
Scaling an application on Heroku is equivalent to changing the number of dynos that are running. Scale the number of web dynos to zero:
$ heroku ps:scale web=0
Access the app again by hitting refresh on the web tab, or heroku open
to open it in a web tab. You will get an error message because you no longer have any web dynos available to serve requests.
Scale it up again:
$ heroku ps:scale web=1
For abuse prevention, scaling a non-free application to more than one dyno requires account verification.
Declare app dependencies
Heroku recognizes an app as Gradle by the existence of a gradlew
orbuild.gradle
file in the root directory. The demo app you deployed already has a build.gradle
(see it here). Here’s an excerpt:
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile 'org.springframework.boot:spring-boot-starter'
compile 'org.springframework.boot:spring-boot-starter-web'
...
}
The build.gradle
file specifies dependencies that should be installed with your application. When an app is deployed, Heroku reads this file and installs the dependencies using the ./gradlew
command.
Another file, system.properties
, determines the version of Java to use (Heroku supports many different versions). The contents of this file, which is optional, is quite straightforward:
java.runtime.version=1.8
Run the Gradle build
in your local directory to install the dependencies, preparing your system for running the app locally. Note that this app requires Java 8, but that you can push your own apps using a different version of Java:
On Windows, run this comannd
> gradlew.bat clean build
On Mac and Linux run this command:
$ ./gradlew clean build
In either case, you’ll see output like this:
:clean
:compileKotlin
Using kotlin incremental compilation
:compileJava NO-SOURCE
:copyMainKotlinClasses
:processResources
:classes
:jar
:findMainClass
:startScripts
:distTar
:distZip
:bootRepackage
:assemble
:compileTestKotlin NO-SOURCE
:compileTestJava NO-SOURCE
:copyTestKotlinClasses
:processTestResources NO-SOURCE
:testClasses UP-TO-DATE
:test NO-SOURCE
:check UP-TO-DATE
:build
BUILD SUCCESSFUL
Total time: 6.177 secs
If you see an error such as Unsupported major.minor version 52.0
, then Gradle is trying to use Java 7. Check that your JAVA_HOME
environment variable is set correctly.
The Gradle process, by virtue of the Spring Boot plugin, will package the application in the build/libs/kotlin-getting-started-1.0.jar
file. If you’re not using SPring Boot, you will need to vendor your dependencies manually as described in the Deploying Gradle Apps on Heroku guide.
Once dependencies are installed, you will be ready to run your app locally.
Run the app locally
Now start your application locally using the heroku local
command, which was installed as part of the Heroku CLI (make sure you’ve already run gradlew clean build
too):
$ heroku local web
[OKAY] Loaded ENV .env File as KEY=VALUE Format
10:15:41 AM web.1 | _ _ _
10:15:41 AM web.1 | | | | | | |
10:15:41 AM web.1 | | |__| | ___ _ __ ___ | | ___ _
10:15:41 AM web.1 | | __ |/ _ \ '__/ _ \| |/ / | | |
10:15:41 AM web.1 | | | | | __/ | | (_) | <| |_| |
10:15:41 AM web.1 | |_| |_|\___|_| \___/|_|\_\\__,_|
10:15:41 AM web.1 | :: Built with Spring Boot :: 1.5.3.RELEASE
...
10:15:58 AM web.1 | 2017-04-20 10:15:46.933 INFO 71653 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 5000 (http)
10:15:58 AM web.1 | 2017-04-20 10:15:46.940 INFO 71653 --- [ main] com.example.Main : Started Main in 6.057 seconds (JVM running for 7.178)
Just like Heroku, heroku local
examines the Procfile
to determine what to run.
Open http://localhost:5000 with your web browser. You should see your app running locally.
To stop the app from running locally, go back to your terminal window and press Ctrl
+C
to exit.
Push local changes
In this step you’ll learn how to propagate a local change to the application through to Heroku. As an example, you’ll modify the application to add an additional dependency and the code to use it.
Modify build.gradle
to include a dependency for jscience
. The dependencies
section should include something like this:
compile 'org.jscience:jscience:4.3.1'
Modify src/main/kotlin/com/example/Controller.kt
so that it imports this library at the start, by including the following imports:
import javax.measure.unit.SI
import javax.measure.quantity.Mass
import org.jscience.physics.model.RelativisticModel
import org.jscience.physics.amount.Amount
And modify the get("/hello",...)
method so that it reads like this:
@RequestMapping("/hello")
internal fun hello(model: MutableMap<String, Any>): String {
RelativisticModel.select()
val m = Amount.valueOf("12 GeV").to(SI.KILOGRAM)
model.put("science", "E=mc^2: 12 GeV = $m")
return "hello"
}
Here’s the final source code for Controller.kt
- yours should look similar. Here’s a diff of all the local changes you should have made.
Now test locally:
$ ./gradlew build
$ heroku local web
Visiting your application on the /hello
route at http://localhost:5000/hello, you should see some great scientific conversions displayed:
E=mc^2: 12 GeV = (2.139194076302506E-26 ± 1.4E-42) kg
Now deploy. Almost every deploy to Heroku follows this same pattern. First, add the modified files to the local git repository:
$ git add .
Now commit the changes to the repository:
$ git commit -m "Demo"
Now deploy, just as you did previously:
$ git push heroku master
Finally, check that everything is working:
$ heroku open hello
Provision add-ons
Add-ons are third-party cloud services that provide out-of-the-box additional services for your application, from persistence through logging to monitoring and more.
By default, Heroku stores 1500 lines of logs from your application. However, it makes the full log stream available as a service - and several add-on providers have written logging services that provide things such as log persistence, search, and email and SMS alerts.
In this step you will provision one of these logging add-ons, Papertrail.
Provision the papertrail logging add-on:
$ heroku addons:create papertrail
Adding papertrail on young-spire-55658... done, v8 (free)
Welcome to Papertrail. Questions and ideas are welcome (support@papertrailapp.com). Happy logging!
Use `heroku addons:docs papertrail` to view documentation.
To help with abuse prevention, provisioning an add-on requires account verification. If your account has not been verified, you will be directed to visit the verification site.
The add-on is now deployed and configured for your application. You can list add-ons for your app like so:
$ heroku addons
To see this particular add-on in action, visit your application’s Heroku URL a few times. Each visit will generate more log messages, which should now get routed to the papertrail add-on. Visit the papertrail console to see the log messages:
$ heroku addons:open papertrail
Your browser will open up a Papertrail web console, showing the latest log events. The interface lets you search and set up alerts:
Start a one-off dyno
You can run a command, typically scripts and applications that are part of your app, in a one-off dyno using the heroku run
command. It can also be used to launch a REPL process attached to your local terminal for experimenting in your app’s environment, or code that you deployed with your application:
$ heroku run bash
Running `bash` attached to terminal... up, run.9640
~ $ java -version
openjdk version "1.8.0_212-heroku"
OpenJDK Runtime Environment (build 1.8.0_212-heroku-b03)
OpenJDK 64-Bit Server VM (build 25.212-b03, mixed mode)
If you receive an error, Error connecting to process
, then you may need to configure your firewall.
Don’t forget to type exit
to exit the shell and terminate the dyno.
Define config vars
Heroku lets you externalise configuration - storing data such as encryption keys or external resource addresses in config vars.
At runtime, config vars are exposed as environment variables to the application. For example, modify src/main/kotlin/com/example/Controller.java
so that the method repeats grabs an energy value from the ENERGY
environment variable:
@RequestMapping("/hello")
internal fun hello(model: MutableMap<String, Any>): String {
RelativisticModel.select()
val energy = System.getenv().get("ENERGY");
val m = Amount.valueOf(energy).to(SI.KILOGRAM)
model.put("science", "E=mc^2: 12 GeV = $m")
return "hello"
}
Now compile the app again so that this change is integrated by running gradlew clean build
.
heroku local
will automatically set up the environment based on the contents of the .env
file in your local directory. In the top-level directory of your project there is already a .env
file that has the following contents:
ENERGY=20 GeV
If you run the app with heroku local
and visit it at http://localhost:5000/hello, you’ll see the conversion value for 20 GeV.
To set the config var on Heroku, execute the following:
$ heroku config:set ENERGY="20 GeV"
Setting config vars and restarting young-spire-55658... done, v10
ENERGY: 20 GeV
View the config vars that are set using heroku config
:
$ heroku config
== young-spire-55658 Config Vars
PAPERTRAIL_API_TOKEN: erdKhPeeeehIcdfY7ne
ENERGY: 20 GeV
...
Deploy your changed application to Heroku to see this in action.
Use a database
The add-on marketplace has a large number of data stores, from Redis and MongoDB providers, to Postgres and MySQL. In this step you will learn about the free Heroku Postgres add-on.
A database is an add-on, and so you can find out a little more about the database provisioned for your app using the addons
command in the CLI:
$ heroku addons
=== Resources for young-spire-55658
Plan Name Price
--------------------------- ------------------ -----
heroku-postgresql:hobby-dev singing-aptly-6889 free
papertrail:choklad gazing-nimbly-9108 free
=== Attachments for young-spire-55658
Name Add-on Billing App
---------- ------------------ -----------------
DATABASE singing-aptly-6889 young-spire-55658
PAPERTRAIL gazing-nimbly-9108 young-spire-55658
Listing the config vars for your app will display the URL that your app is using to connect to the database, DATABASE_URL
:
$ heroku config
=== young-spire-55658 Config Vars
DATABASE_URL: postgres://qplhasewkhqyxp:YXDPSRus9MrU4HglCPzjhOevee@ec2-54-204-47-58.compute-1.amazonaws.com:5432/dc9qsdnghia6v1
...
Heroku also provides a pg
command that shows a lot more:
$ heroku pg
== HEROKU_POSTGRESQL_BLUE_URL (DATABASE_URL)
Plan: Hobby-dev
Status: Available
Connections: 0
PG Version: 9.3.3
Created: 2014-08-08 13:54 UTC
Data Size: 6.5 MB
Tables: 0
Rows: 0/10000 (In compliance)
Fork/Follow: Unsupported
Rollback: Unsupported
This indicates I have a hobby database (free), running Postgres 9.3.3, with a single row of data.
The example app you deployed already has database functionality, which you should be able to reach by visiting your app’s URL and appending /db
. For example, if your app was deployed to https://wonderful-app-287.herokuapp.com/
then visit https://wonderful-app-287.herokuapp.com/db
.
The code to access the database is straightforward. Here’s the method to insert values into a table called tick
:
@Value("\${spring.datasource.url}")
private var dbUrl: String? = null
@Autowired
lateinit private var dataSource: DataSource
...
@RequestMapping("/db")
internal fun db(model: MutableMap<String, Any>): String {
val connection = dataSource.getConnection()
try {
val stmt = connection.createStatement()
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS ticks (tick timestamp)")
stmt.executeUpdate("INSERT INTO ticks VALUES (now())")
val rs = stmt.executeQuery("SELECT tick FROM ticks")
val output = ArrayList<String>()
while (rs.next()) {
output.add("Read from DB: " + rs.getTimestamp("tick"))
}
model.put("records", output)
return "db"
} catch (e: Exception) {
connection.close()
model.put("message", e.message ?: "Unknown error")
return "error"
}
}
@Bean
@Throws(SQLException::class)
fun dataSource(): DataSource {
if (dbUrl?.isEmpty() ?: true) {
return HikariDataSource()
} else {
val config = HikariConfig()
config.jdbcUrl = dbUrl
return HikariDataSource(config)
}
}
This ensures that when you access your app using the /db
route, a new row will be added to the tick
table, and all the rows will then be returned so that they can be rendered in the output.
The HikariCP database connection pool is initialized with the configuration value spring.datasource.url
, which is defined in src/main/resources/application.properties
like this:
spring.datasource.url: ${JDBC_DATABASE_URL:}
This sets spring.datasource.url
to the value in the JDBC_DATABASE_URL
environment variable, set by the database add-on, and establishes a pool of connections to the database.
Deploy your change to Heroku. First commit the changes to git, and then git push heroku master
.
Now, when you access your app’s /db
route, you will see something like this:
Database Output
* Read from DB: 2014-08-08 14:48:25.155241
* Read from DB: 2014-08-08 14:51:32.287816
* Read from DB: 2014-08-08 14:51:52.667683
Assuming that you have Postgres installed locally, use the heroku pg:psql
command to connect to the remote database and see all the rows:
$ heroku pg:psql
heroku pg:psql
psql (9.3.2, server 9.3.3)
SSL connection (cipher: DHE-RSA-AES256-SHA, bits: 256)
Type "help" for help.
=> SELECT * FROM ticks;
tick
----------------------------
2014-08-08 14:48:25.155241
2014-08-08 14:51:32.287816
2014-08-08 14:51:52.667683
2014-08-08 14:51:53.1871
2014-08-08 14:51:54.75061
2014-08-08 14:51:55.161848
2014-08-08 14:51:56.197663
2014-08-08 14:51:56.851729
(8 rows)
=> \q
Read more about Heroku PostgreSQL.
A similar technique can be used to install MongoDB or Redis add-ons.
Next steps
You now know how to deploy an app, change its configuration, view logs, scale, and attach add-ons.
Here’s some recommended reading. The first, an article, will give you a firmer understanding of the basics. The last is a pointer to the main Java category here on Dev Center:
- Read How Heroku Works for a technical overview of the concepts you’ll encounter while writing, configuring, deploying and running applications.
- Read Deploying Java Apps on Heroku to understand how to take an existing Java app and deploy it to Heroku.
- Visit the Java category to learn more about developing and deploying Java applications.