This tutorial will have you deploying a Ruby app in minutes.
Hang on for a few more minutes to learn how it all works, so you can make the most out of Heroku.
The tutorial assumes that you have:
gem install bundler
If you are running on Windows, consider following Getting Started with Ruby on Heroku (Microsoft Windows) instead - it uses a more Windows-friendly local tooling.
If you don’t follow the Windows guide, note that you cannot run
bundle install as you may need to install OpenSSL and the Puma web server manually.
Verify the file is in the correct location:
$ dir c:\openssl bin include lib ssl
$ gem install puma -- --with-opt-dir=c:\openssl
Once this finishes run:
$ bundle update puma
In this step you will install the Heroku Toolbelt. This provides you access to the Heroku Command Line Interface (CLI), which can be used for managing and scaling your applications and add-ons. A key part of the toolbelt is the
heroku local command, which can help in running your applications locally.
Once installed, you can use the
heroku command from your command shell.
Log in using the email address and password you used when creating your Heroku account:
$ heroku login Enter your Heroku credentials. Email: firstname.lastname@example.org Password: ...
Authenticating is required to allow both the heroku and git commands to operate.
Note that if you’re behind a firewall that requires use of a proxy to connect with external HTTP/HTTPS services, you can set the
HTTPS_PROXY environment variables in your local development environment before running the
In this step, you will prepare a simple application that can be deployed.
Execute the following commands to clone the sample application:
$ git clone https://github.com/heroku/ruby-getting-started.git $ cd ruby-getting-started
You now have a functioning git repository that contains a simple application as well as a
Gemfile file, which is used by Ruby’s dependency manager, bundler.
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 polar-inlet-4930... done, stack is cedar-14 http://polar-inlet-4930.herokuapp.com/ | https://git.heroku.com/polar-inlet-4930.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
polar-inlet-4930) for your app, or you can pass a parameter to specify your own app name.
Now deploy your code:
$ git push heroku master Fetching repository, done. Counting objects: 10, done. Delta compression using up to 4 threads. Compressing objects: 100% (6/6), done. Writing objects: 100% (6/6), 876 bytes | 0 bytes/s, done. Total 6 (delta 4), reused 0 (delta 0) remote: -----> Ruby app detected remote: -----> Compiling Ruby/Rails remote: -----> Using Ruby version: ruby-2.2.3 remote: -----> Installing dependencies using 1.7.12 remote: Running: bundle install --without development:test --path vendor/bundle --binstubs vendor/bundle/bin -j4 --deployment remote: Fetching gem metadata from https://rubygems.org/........... remote: Fetching additional metadata from https://rubygems.org/.. remote: Using rake 10.4.2 .... remote: Bundle completed (38.43s) remote: Cleaning up the bundler cache. remote: -----> Preparing app for Rails asset pipeline remote: Running: rake assets:precompile remote: -----> Discovering process types remote: Procfile declares types -> web remote: Default types for Ruby -> console, rake, worker remote: remote: -----> Compressing... done, 30.7MB remote: -----> Launching... done, v16 remote: https://pacific-river-8854.herokuapp.com/ deployed to Heroku remote: remote: Verifying deploy... done. To email@example.com:polar-inlet-4930.git 2e435c5..035d5f5 master -> master
The application is now deployed.
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
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 2014-07-07T11:42:26.829065+00:00 heroku[web.1]: Starting process with command `bundle exec puma -C config/puma.rb` 2014-07-07T11:42:35.334415+00:00 app[web.1]: I, [2014-07-07T11:42:35.334301 #2] INFO -- : listening on addr=0.0.0.0:19146 fd=9 2014-07-07T11:42:35.707657+00:00 app[web.1]: I, [2014-07-07T11:42:35.707293 #5] INFO -- : worker=0 ready 2014-07-07T11:42:35.772074+00:00 app[web.1]: I, [2014-07-07T11:42:35.771727 #11] INFO -- : worker=2 ready 2014-07-07T11:42:35.767750+00:00 app[web.1]: I, [2014-07-07T11:42:35.764688 #2] INFO -- : master process ready 2014-07-07T11:42:35.777268+00:00 app[web.1]: I, [2014-07-07T11:42:35.777006 #8] INFO -- : worker=1 ready 2014-07-07T11:42:35.618291+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.
Control+C to stop streaming the logs.
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.
Procfile in the example app you deployed looks like this:
web: bundle exec puma -C config/puma.rb
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. The command used here is to run puma (the web server), passing in a configuration file.
Procfiles can contain additional process types. For example, you might declare one for a background worker process that processes items off of a queue.
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
You can check how many dynos are running using the
$ heroku ps === web (Free): `bundle exec puma -C config/puma.rb` web.1: up 2015/05/12 11:28:21 (~ 4m ago)
By default, your app is deployed on a free dyno. Free dynos will sleep after a half hour of inactivity and they can be active (receiving traffic) for no more than 18 hours a day before going to sleep. If a free dyno is sleeping, and it hasn’t exceeded the 18 hours, any web request will wake it. This causes a delay of a few seconds for the first request upon waking. Subsequent requests will perform normally.
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.
For abuse prevention, scaling the application requires account verification. If your account has not been verified, you will be directed to visit the verification site.
Heroku recognizes an app as a Ruby app by the existence of a
Gemfile file in the root directory.
The demo app you deployed already has a
Gemfile, and it looks something like this:
Gemfile file specifies the dependencies that should be installed with your application. You can also use it to determine the version of Ruby that will be used to run your application on Heroku.
When an app is deployed, Heroku reads this file and installs the appropriate node version together with the dependencies using the
bundle install command.
A prerequisite to running any app locally is to install the dependencies locally as well. This particular Gemfile has a dependency
pg which will only resolve if you have Postgres installed locally. Please install Postgres before you proceed.
bundle install in your local directory to install the dependencies, preparing your system for running the app locally:
$ bundle install Using rake 10.4.2 Using i18n 0.7.0 Using json 1.8.2 .... Using puma 2.9.1 Your bundle is complete!
Once dependencies are installed, you will be ready to run your app locally.
Running apps locally in your own dev environment does require some effort. Rails typically requires a database - and this sample application uses Postgres. Check out these instructions for a local install.
The Rails app also uses a database, so you’ll have to create the appropriate database and table using the rake task:
$ bundle exec rake db:create db:migrate == 20140707111715 CreateWidgets: migrating ==================================== -- create_table(:widgets) -> 0.0076s == 20140707111715 CreateWidgets: migrated (0.0077s) ===========================
Now start your application locally using the
heroku local command, which was installed as part of the Toolbelt:
$ heroku local web 13:15:47 web.1 | started with pid 67489 13:15:47 web.1 | I, [2014-07-07T13:15:47.655153 #67489] INFO -- : Refreshing Gem list 13:15:48 web.1 | I, [2014-07-07T13:15:48.495226 #67489] INFO -- : listening on addr=0.0.0.0:5000 fd=10 13:15:48 web.1 | I, [2014-07-07T13:15:48.621967 #67489] INFO -- : master process ready 13:15:48 web.1 | I, [2014-07-07T13:15:48.624523 #67491] INFO -- : worker=0 ready 13:15:48 web.1 | I, [2014-07-07T13:15:48.626285 #67492] INFO -- : worker=1 ready 13:15:48 web.1 | I, [2014-07-07T13:15:48.627737 #67493] INFO -- : worker=2 ready
Just like Heroku,
heroku local examines the
Procfile to determine what to run.
Your app will now be running at localhost:5000. Test that it’s working with
curl or a web browser, then Ctrl-C to exit.
heroku local doesn’t just run your app - it also sets “config vars”, something you’ll encounter in a later tutorial.
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.
Gemfile to include a dependency for the
cowsay gem by including a line
source 'https://rubygems.org' ruby '2.2.3' gem 'cowsay' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' gem 'rails', '4.2.0' ...
app/views/welcome/index.erb so that it uses this gem, by changing the file so that its first few lines read as follows:
<pre> <%= Cowsay.say("Hello") %> </pre> ...
Now test locally:
$ bundle install $ heroku local
Visiting your application at localhost:5000. You should see a cute ASCII picture displayed.
Now deploy this local change to Heroku!
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
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 when certain conditions are met.
Provision the papertrail logging add-on:
$ heroku addons:create papertrail Adding papertrail on polar-inlet-4930... done, v11 (free) Welcome to Papertrail. Questions and ideas are welcome (firstname.lastname@example.org). 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
A console will open up, showing the latest log events, and providing you with an interface to search and set up alerts:
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:
$ heroku run rails console Running `rails console` attached to terminal... up, run.1594 Loading production environment (Rails 4.2.0) irb(main):001:0>
If you receive an error,
Error connecting to process, then you may need to configure your firewall.
When the console starts, it has your entire app loaded. For example, you can type
puts Cowsay.say("hi") and an animal saying “hi” will be displayed. Type
exit to quit the console.
irb(main):001:0> puts Cowsay.say("hi") ____ | hi | ---- \ \ .--. |o_o | |:_/ | // \ \ (| | ) /'\_ _/`\ \___)=(___/ => nil irb(main):002:0> exit
To get a real feel for how dynos work, you can create another one-off dyno and run the
bash command, which opens up a shell on that dyno. You can then execute commands there. Each dyno has its own ephemeral filespace, populated with your app and its dependencies - once the command completes (in this case,
bash), the dyno is removed:
$ heroku run bash Running `bash` attached to terminal... up, run.1421 ~ $ ls app config db Gemfile.lock log public README.rdoc tmp bin config.ru Gemfile lib Procfile Rakefile test vendor ~ $ exit exit
Don’t forget to type
exit to exit the shell and terminate the dyno.
Heroku lets you externalize 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
app/views/welcome/index.erb so that the method repeats an action depending on the value of the
TIMES environment variable. Change the file so that its first few lines read as follows:
<% for i in 0..(ENV['TIMES'] ? ENV['TIMES'].to_i : 2) do %> <p>Hello World #<%= i %>!</p> <% end %>
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, create a file called
.env that has the following contents:
If you run the app with
heroku local, you’ll see “Hello World” ten times.
To set the config var on Heroku, execute the following:
$ heroku config:set TIMES=10
View the config vars that are set using
$ heroku config == polar-inlet-4930 Config Vars PAPERTRAIL_API_TOKEN: erdKhPeeeehIcdfY7ne TIMES: 10
Deploy your changed application to Heroku to see this in action.
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 that is provisioned automatically on all Rails app deploys.
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 === polar-inlet-4930 Configured Add-ons heroku-postgresql:hobby-dev HEROKU_POSTGRESQL_BROWN papertrail:choklad
Listing the config vars for your app will display the URL that your app is using to connect to the database,
$ heroku config === polar-inlet-4930 Config Vars DATABASE_URL: postgres://xx:yyy@host:5432/d8slm9t7b5mjnd HEROKU_POSTGRESQL_BROWN_URL: postgres://xx:yyy@host:5432/d8slm9t7b5mjnd ...
Heroku also provides a
pg command that shows a lot more:
$ heroku pg === HEROKU_POSTGRESQL_BROWN_URL (DATABASE_URL) Plan: Hobby-dev Status: Available Connections: 0 PG Version: 9.3.3 Created: 2014-07-07 11:30 UTC Data Size: 6.6 MB Tables: 2 Rows: 1/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 - it has a controller and database model for widgets - which you should be able to reach by visiting your app’s URL and appending ‘/widgets’.
If you do visit the URL, you’ll see an error page appear. Check out the error message in using
heroku logs or in Papertrail, and you’ll see something like this:
2014-07-08T14:52:37.884178+00:00 app[web.1]: Started GET "/widgets" for 220.127.116.11 at 2014-07-08 14:52:37 +0000 2014-07-08T14:52:38.162312+00:00 heroku[router]: at=info method=GET path="/widgets" host=fox828228.herokuapp.com request_id=3755bb46-4de2-4434-a13a-26ec73e53694 fwd="18.104.22.168" dyno=web.1 connect=0 service=294 status=500 bytes=955 2014-07-08T14:52:38.078295+00:00 app[web.1]: Processing by WidgetsController#index as HTML .... 2014-07-08T14:52:38.146062+00:00 app[web.1]: PG::UndefinedTable: ERROR: relation "widgets" does not exist
This indicates that while we could connect to the database, the necessary table wasn’t found. In Rails, you can fix that by running
rake db:migrate. To execute this command on Heroku, run it in a one-off dyno like so:
$ heroku run rake db:migrate Running `rake db:migrate` attached to terminal... up, run.3559 Migrating to CreateWidgets (20140707111715) == 20140707111715 CreateWidgets: migrating ==================================== -- create_table(:widgets) -> 0.0244s == 20140707111715 CreateWidgets: migrated (0.0247s) ===========================
Just like your web process type runs in a dyno, so too did this rake command. Heroku effectively boots a new dyno, adds in your prepared app, and then executes the command in that context - and afterwards removes the dyno. As the dyno performs its actions on a connected add-on, that’s just perfect.
Now if you visit the
/widgets page of your app again, you’ll be able to list and create Widget records.
You can also interact directly with the database if you have Postgres installed locally. For example, here’s how to connect to the database using
psql and execute a query:
$ heroku pg:psql d8slm9t7b5mjnd=> select * from widgets; id | name | description | stock | created_at | updated_at ----+-----------+--------------+-------+----------------------------+---------------------------- 1 | My Widget | It's amazing | 100 | 2014-07-08 15:05:13.330566 | 2014-07-08 15:05:13.330566 (1 row)
Read more about Heroku PostgreSQL.
You now know how to deploy an app, change its configuration, view logs, scale, and attach add-ons.
Here’s some recommended reading: