Codementor Events

Deploying a Crystal Application to Heroku

Published Aug 25, 2015Last updated Feb 09, 2017

Crystal is a typed, LLVM compiled language that
reads (mostly) as Ruby. It's a modern language that comes bundled with support
for WebSockets, OAuth and other niceties.

Even at its early stage, there are already more than a couple web frameworks
gaining popularity in the community. We're going to use
Amethyst, which is currently the most
popular one (as far as GitHub stars go).

Getting the dependencies

You should be able to find out how to install Crystal on your system, on the official
website. Once you have it installed you'll need to create a new directory for
the project and create a file that lists Amethyst as a dependency.

$ mkdir hello_subvisual
$ cd hello_subvisual
$ touch Projectfile

The Projectfile is Crystal's equivalent to Ruby's Gemfile or NPM's
package.json, and it should have the following content:

deps do
  github "Codcore/amethyst"
  github "spalger/crystal-mime"
end

Make sure you use double quotes around the repository names, because there are no
single quoted strings in Crystal.

At the moment of writing there is no central repository for Crystal libraries
(which are called shards). They all just "live" on GitHub repositories. Also, it
does not handle recursive dependencies, that's why we need to specify
crystal-mime as a dependency. This should be fixed soon enough, but if you
wish to know more about the project trying to solve these issues, follow
shards on GitHub.

To fetch the listed dependencies, run crystal deps. This will create a libs
directory that contains the source files of the cloned repositories, alongside
with a .deps.lock file, a .deps and a .crystal directories. They are all
needed for Crystal to function properly, but you shouldn't have to worry too
much about them.

Great! You are now ready to start developing your application.

My first Crystal web application

The focus of this article is not to explain how Amethyst works, they do a pretty
good job at that themselves, in the project's README. We will just copy their
hello world example and use that
as our application, modifying only the name we are greeting. We'll call it
app.cr and here's how it should look like:

require "amethyst"

class WorldController < Base::Controller
  actions :hello

  view "hello", "#{__DIR__}/views"
  def hello
    @name = "Subvisual"
    respond_to do |format|
      format.html { render "hello" }
    end
  end
end

class HelloWorldApp < Base::App
  routes.draw do
    all "/",      "world#hello"
    get "/hello", "world#hello"
    register WorldController
  end
end

app = HelloWorldApp.new
app.serve

That takes care of routing, the controller and starting the app. The only
missing link for a functional application is the view, which should live under
views/hello.ecr, where ecr stands for embedded crystal, and allows us to
write HTML with some sprinkles of Crystal. Your view can be as simple as:

Hello, <%= name %>

Finally, you should be able to run it with crystal app.cr and access it at
http://localhost:8080.

Going live

We are now at a point where we can create an application on
Heroku. If you haven't yet done it, create an account
on Heroku and install the Heroku Toolbelt.

Crystal is not supported out of the box by Heroku, so we'll need to use a custom
buildpack. You can use the one I created, that uses the latest version of
Crystal:

$ heroku create subvisual-hello --buildpack https://github.com/zamith/heroku-buildpack-crystal

Heroku needs to be able to set the port our app runs on, and the buildpack
assumes it accepts a --port PORT option. We can add that to our code easily
enough.

require "amethyst"
require "option_parser"

class WorldController < Base::Controller
...
end

class HelloWorldApp < Base::App
...
end

server_port = 8080
OptionParser.parse! do |opts|
  opts.on("-p PORT", "--port PORT", "define port to run server") do |port|
    server_port = port.to_i
  end
end
app = HelloWorldApp.new
app.serve(server_port)

All that's left is to create a git repository, add the Heroku remote and push it
there. Don't forget to add .deps, .crystal and libs to .gitignore.

$ git init
$ heroku git:remote -a subvisual-hello
$ git add -A
$ git commit -m "My first Crystal app"
$ git push heroku master

And that's it. You can visit your application's URL and see it live.

More on Crystal

If you liked Crystal and want to know more, watch my talk on Eurucamp 2015.

Discover and read more posts from Luís Ferreira
get started