Friday, August 23, 2013

Deploying Yesod to Heroku with Postgres support

I deployed my first Yesod app today! Deploying to Heroku has gotten way smoother since even a few months ago let me tell you. I read articles with crazy gymnastics like booting up a virtual machine that matches Heroku infrastructure to build a binary on a special deploy branch that you copy and... no. Not doing that.

I like Yesod so far. It feels like a real framework that can make real pages. It was definitely influenced by Rails but one thing it left behind is the creepy Rails magic. Things are explicitly linked together so it makes sense (aside from some of the Haskell constructions which are still foreign to me). Plus these DSLs are startlingly clean. Cabal files are like make meets bundler. Hspec is like rspec without stuttering. But my sycophancy aside, here's how you deploy.

Step 1: a basic Yesod app and local databases

Now edit config/postgresql.yml with the username and databases you created, and remove the production database entry. We'll be reading it from a Heroku environment variable.

Step 2: a new Heroku app and production database

Step 3: have the app ask Heroku for db connection info

Follow these excellent instructions to add the Heroku helper to your app. Two things puzzled me for a while that the article doesn't mention. You need to modify your project .cabal file and add heroku to the end of the build-depends and Helpers.Heroku to the exposed-modules.

Step 4: tell Heroku how to run your app and deploy!

Heroku reads a Procfile to determine how to spawn various types of processes like the web server and workers. Yesod projects come with a Procfile you can copy and modify. It's full of scary comments about the bad old days but you can remove all the comments and keep the last line. So do this:

This is all a one-time thing. The first deploy takes a really long time as it installs all the dependencies. To deploy in the future just do git push heroku master and it's fast and works perfectly.


  1. I am having a problem getting my example app running on Heroku. Maybe one of you wizards knows the answer:

    2013-08-27T15:11:01.764268+00:00 heroku[web.1]: Process exited with status 1
    2013-08-27T15:11:01.779798+00:00 heroku[web.1]: State changed from starting to crashed
    2013-08-27T15:11:09.413024+00:00 heroku[web.1]: Error R99 (Platform error) -> Failed to launch the dyno within 10 seconds
    2013-08-27T15:11:09.413024+00:00 heroku[web.1]: Stopping process with SIGKILL
    2013-08-27T15:21:02.921242+00:00 heroku[web.1]: State changed from crashed to starting
    2013-08-27T15:21:05.475487+00:00 heroku[web.1]: Starting process with command `./dist/build/assay/assay production -p 22725`
    2013-08-27T15:21:06.767885+00:00 app[web.1]: assay: SqlError {sqlState = "", sqlExecStatus = FatalError, sqlErrorMsg = "could not connect to server: Connection refused\n\tIs the server running on host \"localhost\" ( and accepting\n\tTCP/IP connections on port 5432?\n", sqlErrorDetail = "", sqlErrorHint = ""}
    2013-08-27T15:21:08.262682+00:00 heroku[web.1]: Process exited with status 1
    2013-08-27T15:21:08.276326+00:00 heroku[web.1]: State changed from starting to crashed

    It looks like my app isn't talking to the database but I'm sort of lost as to why. Any pointers?

    1. Looks like it's trying to connect to your database with default settings. Did you remove the Production group from config/postgresql.yml and follow the instructions about modifying dbconf in Application.hs?

    2. I must have missed that part. Thanks for pointing that out. This worked great.

  2. Thanks for this! Going to give it a try tonight.

    1. Ugh, having trouble getting the PostgreSQL package to install properly in Windows. I'm going to try MongoDB with this.

    2. Got it working. Huzzah. Ended up going with MongoHQ and I had to modify the code from the Heroku package.

    3. Wow nice work, very cool!

      Think it's possible to modify the Heroku package to parse either postgres or mongodb (perhaps depending on an argument)? If so, consider sending a pull request to

    4. That's the plan. I figure that for compatibility, importing Heroku should still give you a Postgres config. Importing Heroku.Mongo will look for a mongo config.

    5. It's finally working :P. Here's my Helpers/Heroku.hs. Doesn't require the Heroku module yet (until I get some pull requests accepted).