Getting Started with Clojure on Heroku/Cedar
Table of Contents
This quickstart will get you going with Clojure and the Ring web library on the Cedar stack.
Prerequisites
- Basic Clojure knowledge, including an installed version of Leiningen and a JVM.
- Your application must be compatible with Leiningen 1.6.2.
- Your application must run on the OpenJDK version 6.
- A Heroku user account. Signup is free and instant.
Local Workstation Setup
We’ll start by setting up your local workstation with the Heroku command-line client and the Git revision control system; and then logging into Heroku to upload your ssh public key. If you’ve used Heroku before and already have a working local setup, skip to the next section.
| If you have... | Install with... |
|---|---|
| Mac OS X | Download OS X package |
| Windows | Download Windows .exe installer |
| Ubuntu Linux | apt-get repository |
| Other |
Tarball (add contents to your $PATH) |
Once installed, you’ll have access to 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: adam@example.com
Password:
Could not find an existing public key.
Would you like to generate one? [Yn]
Generating new SSH public key.
Uploading ssh public key /Users/adam/.ssh/id_rsa.pub
Press enter at the prompt to upload your existing ssh key or create a new one, used for pushing code later on.
Write Your App
You may be starting from an existing app. If not, here’s a simple “hello, world” sourcefile you can use:
src/demo/web.clj
(ns demo.web
(:use ring.adapter.jetty))
(defn app [req]
{:status 200
:headers {"Content-Type" "text/plain"}
:body "Hello, world"})
(defn -main [port]
(run-jetty app {:port (Integer. port)}))
Declare Dependencies In project.clj
Cedar recognizes an app as Clojure by the existence of a project.clj file.
Here’s an example project.clj for the Clojure/Ring app we created above:
project.clj
(defproject hello-world "0.0.1"
:dependencies [[org.clojure/clojure "1.3.0"]
[ring/ring-jetty-adapter "1.0.1"]])
Run lein deps to install your dependencies locally.
Prevent build artifacts from going into revision control by creating this file:
.gitignore
lib
Declare Process Types With Foreman/Procfile
To run your web process, you need to declare what command to use. In this case, we simply need to execute our single Clojure namespace. We’ll use Procfile to declare how our web process type is run.
Here’s a Procfile for the sample app we’ve been working on:
web: lein run -m demo.web $PORT
Now that you have a Procfile, you can start your application with Foreman:
$ foreman start
Your app will come up on port 5000. Test that it’s working with curl or a web browser, then Ctrl-C to exit.
Store Your App in Git
We now have the three major components of our app: dependencies in project.clj, process types in Procfile, and our application source in src/demo/web.clj. Let’s put it into Git:
$ git init
$ git add .
$ git commit -m "init"
Deploy to Heroku/Cedar
Create the app on the Cedar stack:
$ heroku create --stack cedar
Creating glowing-snow-27... done
Created http://glowing-snow-27.herokuapp.com/ | git@heroku.com:glowing-snow-27.git
Git remote heroku added
Deploy your code:
$ git push heroku master
Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (7/7), 710 bytes, done.
Total 7 (delta 0), reused 0 (delta 0)
-----> Heroku receiving push
-----> Clojure app detected
-----> Installing Leiningen
Downloading: leiningen-1.6.2-standalone.jar
Downloading: rlwrap-0.3.7
Writing: lein script
-----> Installing dependencies with Leiningen
Running: LEIN_NO_DEV=y lein deps
Downloading: org/clojure/clojure/1.3.0/clojure-1.3.0.pom from central
Downloading: ring/ring-jetty-adapter/1.0.1/ring-jetty-adapter-1.0.1.pom from central
...
Copying 11 files to /tmp/build_22n0pvoq4rj3p/lib
-----> Procfile declares process types -> web
Compiled slug size is 3.9MB
-----> Launching... done, v1
http://glowing-snow-27.herokuapp.com deployed to Heroku
To git@heroku.com:glowing-snow-27.git
* [new branch] master -> master
Before looking at the app on the web, we’ll need to scale the web process:
$ heroku ps:scale web=1
Scaling web processes... done, now running 1
Now, let’s check the state of the app’s processes:
$ heroku ps
Process State Command
------------ ------------------ --------------------------------------------
web.1 up for 10s lein run -m demo.web
The web process is up. Review the logs for more information:
$ heroku logs
2011-03-16T03:28:32-07:00 heroku[web.1]: Running process with command: `lein run -m demo.web`
2011-03-16T03:28:37-07:00 app[web.1]: 2011-03-16 10:28:37.181:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
2011-03-16T03:28:37-07:00 app[web.1]: 2011-03-16 10:28:37.182:INFO::jetty-6.1.26
2011-03-16T03:28:40-07:00 app[web.1]: 2011-03-16 10:28:40.223:INFO::Started SocketConnector@0.0.0.0:20184
2011-03-16T03:28:40-07:00 heroku[web.1]: State changed from starting to up
...
Looks good. We can now visit the app with heroku open.
Console
Cedar allows you to launch a REPL process attached to your local terminal for experimenting in your app’s environment:
Running heroku run lein repl uses a simplified version of the repl task provided by Leiningen.
$ heroku run lein repl
Running lein repl attached to terminal... up, run.1
Clojure 1.3.0
user=>
This console has your application code available. For example:
user=> (require 'demo.web)
nil
user=> (demo.web/app {})
{:status 200, :headers {"Content-Type" "text/plain"}, :body "Hello, world"}
One-off Scripts
You can run a one-off Clojure script attached to the terminal in the same way, as long as the script exists in your deployed app. Try making a small script that prints to the console and exits:
src/demo/hi.clj
(ns demo.hi)
(defn -main [& args]
(println "Hello there"))
Commit and deploy this new code:
$ git add src/demo/hi.clj
$ git commit -m "hi"
$ git push heroku master
Run the script with heroku run:
$ heroku run lein run -m demo.hi
Running lein run -m demo.hi attached to terminal... up, run.2
Hello there
Using a SQL Database
By default, Clojure apps aren’t given a SQL database. This is because you might want to use a NoSQL database like Redis or CouchDB, or (as in the case of our sample app above) you don’t need any database at all.
If you do need a SQL database for your app, request one explicitly:
$ heroku addons:add shared-database
Further Reading
- Building a Database-Backed Clojure Web Application
- Clojure Buildpack (for documentation on build options)