Deep-dive on the Next Gen Platform. Join the Webinar!

Skip Navigation
Show nav
Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
    • .NET
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up

Getting Started on Heroku with Scala and Play

Introduction

Complete this tutorial to deploy a sample Scala app to Cedar, the legacy generation of the Heroku platform. To deploy the app to the Fir generation, only available to Heroku Private Spaces, follow this guide instead.

The tutorial assumes that you have:

  • A verified Heroku Account
  • OpenJDK 17 (or newer) installed
  • sbt installed
  • Postgres installed
  • An Eco dynos plan subscription (recommended)

Using dynos and databases to complete this tutorial counts towards your usage. 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

Install the Heroku Command Line Interface (CLI). Use the CLI to manage and scale your app, provision add-ons, view your logs, and run your app locally.

The Heroku CLI requires Git, the popular version control system. If you don’t already have Git installed, complete the following before proceeding:

  • Git installation
  • First-time Git setup

Download and run the installer for your platform:

apple logomacOS

Install Homebrew and run:

$ brew install heroku/brew/heroku

windows logoWindows

Download the appropriate installer for your Windows installation:

64-bit installer

32-bit installer

You can find more installation options for the Heroku CLI here.

After installation, you can use the heroku command from your command shell.

To log in to the Heroku CLI, use the heroku login command:

$ heroku login
heroku: Press any key to open up the browser to login or q to exit:
Opening browser to https://cli-auth.heroku.com/auth/cli/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, click the Log In button on the page.

This authentication is required for the heroku and git commands to work correctly.

If you have any problems installing or using the Heroku CLI, see the main Heroku CLI article for advice and troubleshooting steps.

If you’re behind a firewall that uses a proxy to connect with external HTTP/HTTPS services, set the HTTP_PROXY or HTTPS_PROXY environment variables in your local development environment before running the heroku command.

Prepare the App

If you’re new to Heroku, it’s recommended to complete this tutorial using the Heroku-provided sample application.

If you have your own application that you want to deploy instead, see Preparing a Codebase for Heroku Deployment.

Create a local copy of the sample app by executing the following commands in your local command shell or terminal:

$ git clone https://github.com/heroku/scala-getting-started
$ cd scala-getting-started

This functioning Git repository contains a sample Scala application. It includes a build.sbt file, which is used by sbt, a Scala build tool.

Create Your App

Using a dyno and a database to complete this tutorial counts towards your usage. Delete your app, and database as soon as you’re done to control costs.

 

Apps use Eco dynos if you’re subscribed to Eco by default. Otherwise, it defaults to Basic dynos. The Eco dynos plan is shared across all Eco dynos in your account. It is recommended if you plan on deploying many small apps to Heroku. Learn more here. Eligible students can apply for platform credits through our Heroku for GitHub Students program.

To prepare Heroku to receive your source code, create an app:

$ heroku create
Creating app... done, ⬢ peaceful-inlet-84135
http://peaceful-inlet-84135.herokuapp.com/ | https://git.heroku.com/peaceful-inlet-84135.git

When you create an app, a git remote called heroku is also created and associated with your local git repository. Git remotes are versions of your repository that live on other servers. You deploy your app by pushing its code to that special Heroku-hosted remote associated with your app.

Heroku generates a random name for your app, in this case, peaceful-inlet-84135. You can specify your own app name.

Define a Procfile

Use a Procfile, a text file in the root directory of your application, to explicitly declare what command to execute to start your app.

The Procfile in the example app looks like this:

web: target/universal/stage/bin/scala-getting-started -Dhttp.port=${PORT}

This Procfile 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 is attached to Heroku’s HTTP routing stack and receives web traffic when deployed.

A Procfile can contain additional process types. For example, you can declare a background worker process that processes items off a queue.

Provision a Database

The sample app requires a database. Provision a Heroku Postgres database, one of the add-ons available through the Elements Marketplace. Add-ons are cloud services that provide out-of-the-box additional services for your application, such as logging, monitoring, databases, and more.

An essential-0 Postgres size costs $5 a month, prorated to the minute. Delete your database after completing this guide to minimize costs.

$ heroku addons:create heroku-postgresql:essential-0
Creating heroku-postgresql:essential-0 on ⬢ peaceful-inlet-84135... ~$0.007/hour (max $5/month)
Database should be available soon
postgresql-fitted-70383 is being created in the background. The app will restart when complete...
Use heroku addons:info postgresql-fitted-70383 to check creation progress
Use heroku addons:docs heroku-postgresql to view documentation

Your Heroku app now has access to a Postgres database. The DATABASE_URL environment variable stores the credentials. Heroku also automatically makes a JDBC_DATABASE_URL environment variable available for Scala applications. It contains a JDBC-compatible version of DATABASE_URL.

You can see all the add-ons provisioned with the addons command:

$ heroku addons
Add-on                                       Plan         Price     State
───────────────────────────────────────────  ───────────  ────────  ───────
heroku-postgresql (postgresql-fitted-70383)  essential-0  $5/month  created
 └─ as DATABASE

Deploy the App

Deploy your code. This command pushes the main branch of the sample repo to your heroku remote, which then deploys to Heroku:

$ git push heroku main
remote: Compressing source files... done.
remote: Building source:
remote:
remote: -----> Building on the Heroku-22 stack
remote: -----> Determining which buildpack to use for this app
remote: -----> Play 2.x - Scala app detected
remote: -----> Installing OpenJDK 17... done
remote: -----> Priming Ivy cache... done
remote: -----> Running: sbt compile stage
remote: Downloading sbt launcher for 1.7.2:
remote:   From  https://repo1.maven.org/maven2/org/scala-sbt/sbt-launch/1.7.2/sbt-launch-1.7.2.jar
remote:     To  /tmp/scala_buildpack_build_dir/.sbt_home/launchers/1.7.2/sbt-launch.jar
remote: Downloading sbt launcher 1.7.2 md5 hash:
remote:   From  https://repo1.maven.org/maven2/org/scala-sbt/sbt-launch/1.7.2/sbt-launch-1.7.2.jar.md5
remote:     To  /tmp/scala_buildpack_build_dir/.sbt_home/launchers/1.7.2/sbt-launch.jar.md5
remote:        /tmp/scala_buildpack_build_dir/.sbt_home/launchers/1.7.2/sbt-launch.jar: OK
remote: [info] [launcher] getting org.scala-sbt sbt 1.7.2  (this may take some time)...
remote: [info] [launcher] getting Scala 2.12.16 (for sbt)...
remote:        [info] welcome to sbt 1.7.2 (Azul Systems, Inc. Java 17.0.6)
remote:        [info] loading global plugins from /tmp/scala_buildpack_build_dir/.sbt_home/plugins
remote:        [info] compiling 1 Scala source to /tmp/scala_buildpack_build_dir/.sbt_home/plugins/target/scala-2.12/sbt-1.0/classes ...
remote:        [info] Non-compiled module 'compiler-bridge_2.12' for Scala 2.12.16. Compiling...
remote:        [info]   Compilation completed in 15.389s.
remote:        [info] done compiling
remote:        [info] loading settings for project scala_buildpack_build_dir-build from plugins.sbt ...
remote:        [info] loading project definition from /tmp/scala_buildpack_build_dir/project
remote:        [info] loading settings for project root from build.sbt ...
remote:        [info]   __              __
remote:        [info]   \ \     ____   / /____ _ __  __
remote:        [info]    \ \   / __ \ / // __ `// / / /
remote:        [info]    / /  / /_/ // // /_/ // /_/ /
remote:        [info]   /_/  / .___//_/ \__,_/ \__, /
remote:        [info]       /_/               /____/
remote:        [info]
remote:        [info] Version 2.8.19 running Java 17.0.6
remote:        [info]
remote:        [info] Play is run entirely by the community. Please consider contributing and/or donating:
remote:        [info] https://www.playframework.com/sponsors
remote:        [info]
remote:        [info] Running Play on Java 17 is experimental. Tweaks are necessary:
remote:        [info] https://github.com/playframework/playframework/releases/2.8.15
remote:        [info]
remote:        [info] Executing in batch mode. For better performance use sbt's shell
remote:        [info] compiling 8 Scala sources and 1 Java source to /tmp/scala_buildpack_build_dir/target/scala-2.13/classes ...
remote:        [info] Non-compiled module 'compiler-bridge_2.13' for Scala 2.13.10. Compiling...
remote:        [info]   Compilation completed in 15.043s.
remote:        [info] done compiling
remote:        [success] Total time: 23 s, completed Apr 5, 2023, 9:00:57 AM
remote:        [info] Wrote /tmp/scala_buildpack_build_dir/target/scala-2.13/scala-getting-started_2.13-1.0-SNAPSHOT.pom
remote:        [info] Main Scala API documentation to /tmp/scala_buildpack_build_dir/target/scala-2.13/api...
remote:        [info] Main Scala API documentation successful.
remote:        [success] Total time: 5 s, completed Apr 5, 2023, 9:01:01 AM
remote: -----> Collecting dependency information
remote: -----> Dropping ivy cache from the slug
remote: -----> Dropping sbt boot dir from the slug
remote: -----> Dropping sbt cache dir from the slug
remote: -----> Dropping compilation artifacts from the slug
remote: -----> Discovering process types
remote:        Procfile declares types -> web
remote:
remote: -----> Compressing...
remote:        Done: 108.2M
remote: -----> Launching...
remote:        Released v4
remote:        https://peaceful-inlet-84135.herokuapp.com/ deployed to Heroku
remote:
remote: Verifying deploy... done.
To https://git.heroku.com/peaceful-inlet-84135.git
 * [new branch]      main -> main

By default, apps use Eco dynos if you’re subscribed to Eco. A dyno is a lightweight Linux container that runs the command specified in your Procfile. After deployment, ensure that you have one web dyno running the app. You can check how many dynos are running using the heroku ps command:

$ heroku ps
Eco dyno hours quota remaining this month: 1000h 0m (100%)
Eco dyno usage for this app: 0h 0m (0%)
For more information on Eco dyno hours, see:
https://devcenter.heroku.com/articles/eco-dyno-hours

=== web (Eco): target/universal/stage/bin/scala-getting-started -Dhttp.port=${PORT} (1)
web.1: up 2023/03/09 17:00:28 +0100 (~ 1m ago)

The running web dyno serves requests. Visit the app at the URL shown in the logs. As a handy shortcut, you can open the website with:

$ heroku open

The Eco dynos plan is shared across all Eco dynos in your account and is recommended if you plan on deploying many small apps to Heroku. Eco dynos sleep if they don’t receive any traffic for half an hour. This sleep behavior causes a few seconds delay for the first request upon waking. Eco dynos consume from a monthly, account-level quota of eco dyno hours. As long as you haven’t exhausted the quota, your apps can continue to run.

To avoid dyno sleeping, upgrade to a Basic or Professional dyno type as described in Dyno Types.

Scale the App

Horizontal scaling an application on Heroku is equivalent to changing the number of running dynos.

Scale the number of web dynos to zero:

$ heroku ps:scale web=0

Access the app again by refreshing your browser or running heroku open. You get an error message because your app no longer has any web dynos available to serve requests.

Scale it up again:

$ heroku ps:scale web=1

You can also vertically scale your app by upgrading to larger dynos. See Dyno Types and Scaling Your Dyno Formation for more info.

View Logs

Heroku treats logs as streams of time-ordered events, aggregated from the output streams of all your app and Heroku components. Heroku provides a single stream for all events.

View information about your running app by using one of the logging commands, heroku logs --tail:

$ heroku logs --tail
2023-03-09T17:01:33.946880+00:00 heroku[web.1]: Starting process with command `target/universal/stage/bin/scala-getting-started -Dhttp.port=${PORT}`
2023-03-09T17:01:34.777255+00:00 app[web.1]: Setting JAVA_TOOL_OPTIONS defaults based on dyno size. Custom settings will override them.
2023-03-09T17:01:34.865577+00:00 app[web.1]: Picked up JAVA_TOOL_OPTIONS: -XX:+UseContainerSupport -Xmx300m -Xss512k -XX:CICompilerCount=2 -Dfile.encoding=UTF-8
2023-03-09T17:01:36.959678+00:00 app[web.1]: 2023-03-09 17:01:36 WARN  play.api.http.HttpConfiguration
2023-03-09T17:01:37.096800+00:00 app[web.1]: 2023-03-09 17:01:37 INFO  play.api.Play  Application started (Prod) (no global state)
2023-03-09T17:01:37.700798+00:00 app[web.1]: 2023-03-09 17:01:37 INFO  play.core.server.AkkaHttpServer  Listening for HTTP on /[0:0:0:0:0:0:0:0]:7707
2023-03-09T17:01:38.191846+00:00 heroku[web.1]: State changed from starting to up
2023-03-09T17:01:56.000000+00:00 app[api]: Build succeeded
2023-03-09T17:04:55.627566+00:00 heroku[router]: at=info method=GET path="/" host=peaceful-inlet-84135.herokuapp.com request_id=f7b88a86-0e62-49f8-b37a-a083a558ed0e fwd="85.222.134.3" dyno=web.1 connect=0ms service=196ms status=200 bytes=9081 protocol=https
2023-03-09T17:04:55.932796+00:00 heroku[router]: at=info method=GET path="/assets/stylesheets/main.css" host=peaceful-inlet-84135.herokuapp.com request_id=af71979c-ea8b-4486-af07-0248d59fc5d5 fwd="85.222.134.3" dyno=web.1 connect=0ms service=95ms status=200 bytes=1115 protocol=https
2023-03-09T17:04:55.934057+00:00 heroku[router]: at=info method=GET path="/assets/images/lang-logo.png" host=peaceful-inlet-84135.herokuapp.com request_id=893a88af-6de6-40fa-888b-16488831aef7 fwd="85.222.134.3" dyno=web.1 connect=0ms service=85ms status=200 bytes=1587 protocol=https
2023-03-09T17:04:56.139535+00:00 heroku[router]: at=info method=GET path="/favicon.ico" host=peaceful-inlet-84135.herokuapp.com request_id=8b1dccd0-15b4-47f2-97d0-2df49c09a94b fwd="85.222.134.3" dyno=web.1 connect=0ms service=23ms status=404 bytes=1501 protocol=https

To see more log messages generate, visit your application in the browser first.

To stop streaming the logs, press Control+C.

Provision a Logging Add-on

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, but the full log stream is available as a service. Several add-on providers have logging services that provide things such as log persistence, search, and email and SMS alerts.

In this step, you provision one of these logging add-ons, Papertrail.

Provision the Papertrail logging add-on:

$ heroku addons:create papertrail
Creating papertrail on ⬢ peaceful-inlet-84135... free
Welcome to Papertrail. Questions and ideas are welcome (technicalsupport@solarwinds.com). Happy logging!
Created papertrail-slippery-84785 as PAPERTRAIL_API_TOKEN
Use heroku addons:docs papertrail to view documentation

To see this particular add-on in action, visit your application’s Heroku URL a few times. Each visit generates more log messages, which get routed to the Papertrail add-on. Visit the Papertrail console to see the log messages:

$ heroku addons:open papertrail

Your browser opens up a Papertrail web console that shows the latest log events. The interface lets you search and set up alerts.

Use a Database

Heroku provides managed data services for Postgres and Redis, and the add-on marketplace provides additional data services, including MongoDB and MySQL.

Use the heroku addons command for an overview of the database provisioned for your app:

$ heroku addons

Add-on                                       Plan         Price     State
───────────────────────────────────────────  ───────────  ────────  ───────
heroku-postgresql (postgresql-fitted-70383)  essential-0  $5/month  created
 └─ as DATABASE

papertrail (papertrail-slippery-84785)       choklad      free      created
 └─ as PAPERTRAIL

Listing your app’s config vars displays the URL that your app uses to connect to the database (DATABASE_URL):

$ heroku config
=== peaceful-inlet-84135 Config Vars
DATABASE_URL:         postgres://avhrhofbiyvpct:3ab23026d0fc225bde4544cedabc356904980e6a02a2418ca44d7fd19dad8e03@ec2-23-21-4-7.compute-1.amazonaws.com:5432/d8e8ojni26668k
PAPERTRAIL_API_TOKEN: ChtIUu9fHbij1cBn7y6z

The heroku pg command provides more in-depth information on your app’s Heroku Postgres databases:

$ heroku pg
=== DATABASE_URL
Plan:                  Essential 0
Status:                Available
Connections:           0/20
PG Version:            15.5
Created:               2024-05-01 16:00 UTC
Data Size:             8.6 MB/1.00 GB (0.84%) (In compliance)
Tables:                0
Fork/Follow:           Unsupported
Rollback:              Unsupported
Continuous Protection: Off
Add-on:                postgresql-fitted-70383

Running this command for your app indicates that the app has an essential-0 Postgres database running Postgres 15.5, with no tables.

The example app you deployed already has database functionality, which you can reach by visiting your app’s /database path.

$ heroku open /database

You see something like this:

Read from DB: 2023-03-09 16:58:55.816605
Read from DB: 2023-03-09 16:58:56.728701
Read from DB: 2023-03-09 16:58:57.064755

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
--> Connecting to postgresql-fitted-70383
psql (15.2, server 14.7 (Ubuntu 14.7-1.pgdg20.04+1))
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.

peaceful-inlet-84135::DATABASE=> SELECT * FROM ticks;
            tick
----------------------------
 2023-03-09 16:58:55.816605
 2023-03-09 16:58:56.728701
 2023-03-09 16:58:57.064755
(3 rows)

peaceful-inlet-84135::DATABASE=> \q

The following info illustrates how the example app implements its database functionality. Don’t change your example app code in this step

The code in the example app looks like this:

def db(): Action[AnyContent] = Action { implicit request: Request[AnyContent] =>
    // In this getting started app, we don't use a custom execution context to keep the code and configuration simple.
    // For real-world apps, consult the Play documentation on how to configure custom contexts and how to use them:
    // https://www.playframework.com/documentation/2.8.19/AccessingAnSQLDatabase#Using-a-CustomExecutionContext
    database.withConnection { connection =>
      val statement = connection.createStatement()
      statement.executeUpdate("CREATE TABLE IF NOT EXISTS ticks (tick timestamp)")
      statement.executeUpdate("INSERT INTO ticks VALUES (now())")

      val output = new StringBuilder();
      val resultSet = statement.executeQuery("SELECT tick FROM ticks")
      while (resultSet.next()) {
        output.append("Read from DB: " + resultSet.getTimestamp("tick") + "\n")
      }

      Ok(output.toString())
    }
}

The db method adds a row to the tick table when you access your app using the /database route. It then returns all rows to render in the output.

The Database shown in the example app code is automatically configured and injected by the Play framework. It refers to the values in the conf/application.conf file for the database connection configuration.

The example app has db.default.url set to the value in the JDBC_DATABASE_URL environment variable to establish a pool of connections to the database:

db.default.url = ${JDBC_DATABASE_URL}

The official Heroku Scala buildpack that’s automatically added to your app sets this JDBC_DATABASE_URL environment variable when a dyno starts up. This variable is dynamic and doesn’t appear in your list of configuration variables when running heroku config. You can view it by running the following command:

$ heroku run echo \$JDBC_DATABASE_URL

Read more about Heroku PostgreSQL. You can also install Redis or other data add-ons via heroku addons:create.

Prepare the Local Environment

You must install your app’s dependencies before you can run your app locally.

Run sbt stage in your local directory. This command installs the dependencies, preparing your system to run the app locally.

$ sbt stage
...
[info] Wrote /Users/example-user/projects/scala-getting-started/target/scala-2.13/scala-getting-started_2.13-1.0-SNAPSHOT.pom
[info] Main Scala API documentation to /Users/example-user/projects/scala-getting-started/target/scala-2.13/api...
[info] Main Scala API documentation successful.
[success] Total time: 3 s, completed 9 Mar 2023, 17:48:51

After staging, you can run your app locally but it still requires a Postgres database. Create a local Postgres database and update your local .env file.

heroku local, the command used to run apps locally, automatically sets up your environment based on the .env file in your app’s root directory. Set the JDBC_DATABASE_URL environment variable with your local Postgres database’s connection string:

JDBC_DATABASE_URL=jdbc:postgresql://localhost:5432/scala_database_name

Your local environment is now ready to run your app and connect to the database.

Run the App Locally

Ensure you’ve already run sbt stage before running your app locally.

Start your application locally with the heroku local CLI command:

$ heroku local --port 5001
...
5:26:58 AM web.1 |  2023-03-09 17:58:43 INFO  play.api.db.DefaultDBApi  Database [default] initialized
5:26:58 AM web.1 |  2023-03-09 17:58:43 INFO  play.api.db.HikariCPConnectionPool  Creating Pool for datasource 'default'
5:26:58 AM web.1 |  2023-03-09 17:58:43 INFO  play.api.Play  Application started (Prod) (no global state)
5:26:58 AM web.1 |  2023-03-09 17:58:44 INFO  play.core.server.AkkaHttpServer  Listening for HTTP on /[0:0:0:0:0:0:0:0]:5001

Just like the Heroku platform, heroku local examines your Procfile to determine what command to run.

To see your app running locally, open http://localhost:5001 with your web browser

If you want to access the app’s /database route locally, ensure that your local Postgres database is running before you visit the URL.

To stop the app from running locally, go back to your terminal window and press Control+C to exit.

Push Local Changes

In this step, you make local changes to your app and deploy them to Heroku.

Modify build.sbt to include a dependency for jscience by adding the following code to libraryDependencies:

"org.jscience" % "jscience" % "4.3.1"

In the file app/controllers/Application.scala, add the following import statements for the library:

import org.jscience.physics.amount.Amount
import org.jscience.physics.model.RelativisticModel
import javax.measure.unit.SI

Add the following convert method to Application.scala:

def convert(): Action[AnyContent] = Action { implicit request: Request[AnyContent] =>
  RelativisticModel.select()
  val energy = Amount.valueOf("12 GeV");

  Ok("E=mc^2: " + energy + " = " + energy.to(SI.KILOGRAM))
}

Add a route to the new action in conf/routes:

GET     /convert                    controllers.Application.convert()

Here’s the final source code for Application.scala. Ensure that your changes look similar. Here’s a diff of all the local changes made.

Test your changes locally:

$ sbt stage
...
[info] Wrote /Users/example-user/projects/scala-getting-started/target/scala-2.13/scala-getting-started_2.13-1.0-SNAPSHOT.pom
[success] Total time: 1 s, completed 9 Mar 2023, 18:05:12

$ heroku local --port 5001
...
6:05:29 PM web.1 |  2023-03-09 18:05:15 INFO  play.api.db.DefaultDBApi  Database [default] initialized
6:05:29 PM web.1 |  2023-03-09 18:05:15 INFO  play.api.db.HikariCPConnectionPool  Creating Pool for datasource 'default'
6:05:29 PM web.1 |  2023-03-09 18:05:15 INFO  play.api.Play  Application started (Prod) (no global state)
6:05:29 PM web.1 |  2023-03-09 18:05:15 INFO  play.core.server.AkkaHttpServer  Listening for HTTP on /[0:0:0:0:0:0:0:0]:5001

Visit your application’s /convert path at http://localhost:5001/convert, which displays some scientific conversions:

E=mc^2: 12 GeV = (2.139194076302506E-26 ± 1.4E-42) kg

After testing, deploy your changes. Almost every Heroku deployment follows this same pattern. First, use the git add command to stage your modified files for commit:

$ git add .

Next, commit the changes to the repository:

$ git commit -m "Add convert endpoint"

Now deploy as you did before:

$ git push heroku main

Finally, check that your updated code successfully deployed by opening your browser to that route:

$ heroku open /convert

Define Config Vars

Heroku lets you externalize your app’s configuration by storing data such as encryption keys or external resource addresses in config vars.

At runtime, config vars are exposed to your app as environment variables. For example, modify Application.scala so that the method obtains an energy value from the ENERGY environment variable:

In file app/controllers/Application.scala, change the convert method:

def convert(): Action[AnyContent] = Action { implicit request: Request[AnyContent] =>
  RelativisticModel.select()

  Ok(sys.env.get("ENERGY")
    .map(Amount.valueOf)
    .map(energy => "E=mc^2: " + energy + " = " + energy.to(SI.KILOGRAM))
    .getOrElse("ENERGY environment variable is not set!"))
}

Recompile the app to integrate this change by running sbt stage.

heroku local automatically sets up your local environment based on the .env file in your app’s root directory. Your sample app already includes a .env file with the following contents:

ENERGY=20 GeV

Your local .env file also includes the JDBC_DATABASE_URL variable if you set it during the Run the App Locally step.

Don’t commit the .env file to version control as it often includes secure credentials. Include .env in your repo’s .gitignore file. The sample app repo only includes a .env file as an example for this tutorial step.

Run the app with heroku local --port 5001 and visit http://localhost:5001/convert to see the conversion value for 20 GeV.

Now that you know it works as expected locally, set this variable as a config var on your app running on Heroku. Execute the following:

$ heroku config:set ENERGY="20 GeV"
Setting ENERGY and restarting ⬢ peaceful-inlet-84135... done, v9
ENERGY: 20 GeV

View the app’s config vars using heroku config to verify it’s set correctly:

$ heroku config
=== peaceful-inlet-84135 Config Vars
DATABASE_URL:         postgres://avhrhofbiyvpct:3ab23026d0fc225bde4544cedabc356904980e6a02a2418ca44d7fd19dad8e03@ec2-23-21-4-7.compute-1.amazonaws.com:5432/d8e8ojni26668k
ENERGY:               20 GeV
PAPERTRAIL_API_TOKEN: ChtIUu9fHbij1cBn7y6z

Deploy your local changes to Heroku and visit the /convert route to see your changes in action:

$ git add .
$ git commit -m "Use ENERGY environment variable"
$ git push heroku main
$ heroku open /convert

Start a One-off Dyno

The heroku run command lets you run maintenance and administrative tasks on your app in a one-off dyno. It also lets you launch a REPL process attached to your local terminal for experimenting in your app’s environment or your deployed application code:

$ heroku run java -version
Running java -version on ⬢ peaceful-inlet-84135... up, run.4406 (Eco)
openjdk version "17.0.6" 2023-01-17 LTS
OpenJDK Runtime Environment Zulu17.40+19-CA (build 17.0.6+10-LTS)
OpenJDK 64-Bit Server VM Zulu17.40+19-CA (build 17.0.6+10-LTS, mixed mode, sharing)

If you receive an error, Error connecting to process, configure your firewall.

Remember to type exit to exit the shell and terminate the dyno.

Next Steps

Congratulations! You now know how to deploy an app, change its configuration, scale it, view logs, attach add-ons, and run it locally.

Here’s some recommended reading to continue your Heroku journey:

  • How Heroku Works provides a technical overview of the concepts encountered while writing, configuring, deploying, and running apps.
  • The Scala category provides more in-depth information on developing and deploying Scala apps.
  • The Deployment category provides a variety of powerful integrations and features to help streamline and simplify your deployments.

Remember to delete your example app, and database as soon as you’re done with the tutorial, to control costs.

Delete Your App and Add-on

Remove the app and database from your account. You’re only charged for the resources you used.

This action removes your add-on and any data saved in the database.

$ heroku addons:destroy heroku-postgresql
 ▸    WARNING: Destructive Action
 ▸    This command will affect the app peaceful-inlet-84135
 ▸    To proceed, type peaceful-inlet-84135 or re-run this command with
 ▸    --confirm peaceful-inlet-84135

>

This action permanently deletes your application

$ heroku apps:destroy
 ▸    WARNING: This will delete ⬢ peaceful-inlet-84135 including all add-ons.
 ▸    To proceed, type peaceful-inlet-84135 or re-run this command with
 ▸    --confirm peaceful-inlet-84135

>

You can confirm that your add-on and app are gone with these commands:

$ heroku addons --all
$ heroku apps --all

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure
  • .NET

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing
  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Github
  • LinkedIn
  • heroku.com
  • Terms of Service
  • Privacy (日本語)
  • Cookies
  • Cookie Preferences
  • Your Privacy Choices
  • © 2025 Salesforce.com