Post hero cover

Deploying a Crystal application to Heroku

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.

Luis Zamith

About Luis Zamith

Has worked on the web for a while now, mainly using Ruby and Ruby on Rails. Enjoys open source and giving back to the community, having taught Rails to hundreds of people.
Like what you've read so far? Let's work together.