Heroku and Unicorn: How to Get a 4x Performance Boost


Reading Time: 5 minutes

Update: After the shitstorm surrounding Heroku’s routing they have updated their docs and now regard Unicorn as their default Rails server. They now provide 2x dynos with twice the RAM so you can run bigger applications with unicorn or run more unicorn workers on one server. Last but not least New Relic updated their gem to make sure that the queuing time shown for a Heroku application is correct. We have left the rest of the blogpost untouched as it still reflects how you can set up Unicorn on your Heroku machines. But take the changes in the recent Heroku blogposts into account.

This is the first of a two part series on how we set up Codeship with Heroku. The second part deals with Assets, Sprites and Amazon Cloudfront. This guide is only relevant and tested with the Heroku Cedar stack.

I have had several debates over the last couple of months whether Heroku is the way to go and especially if it is expensive or not. They provide a great service, but their documentation makes them look pretty bad when it comes to price. $35 for basically one single concurrent request seems very expensive, especially when starting out with a new project (although of course the first dyno is free). Heroku provides plenty of resources, but as it only allows to listen on one port you can run only one thin instance (as recommended by their documentation). What we need here is a webserver that listens on one port, but can work through several concurrent requests. Sounds like a job for Unicorn.

What is Unicorn

Unicorn is a ruby http server that starts one master process listening on one port and forks several worker processes. Every incoming client request is handed to a worker by the master and when finished the master returns the result to the client. Thus it only needs to listen on one port, but can work on several concurrent requests. Defunkt wrote a nice blogpost about unicorn some time ago that goes into more detail how GitHub uses it.


To start using Unicorn all you have to do is:

1. Create a Procfile

2. Add unicorn config in config/unicorn.rb

3. Set the default Logger in application.rb (and not just production.rb) to STDOUT, otherwise logging doesn’t work. Thx to @krainboltgreene for mentioning that just setting this in production.rb is not enough.

Unicorn config

You can find all config parameters in the unicorn documentation. Let’s go quickly through the configuration we use for worker_processes: Setting the number of worker processes timeout: Time after which a worker is restarted if unresponsive preload_app: Load the application before forking workers. Set to true if you use NewRelic (which you should) or you won’t see any data before_fork/after_fork: Disconnect in before_fork and reconnect in after_fork for your Database, Resque or other services. Without those handlers there will be regular database errors.

New Relic

Go to the NewRelic Addon of your Heroku application and check your dynos and memory consumption in the dyno tab.

Average memory consumption

Check your Memory Consumption in NewRelic and set the worker_processes accordingly. The average consumption is shown on the Dyno tab of your NewRelic dashboard.


One Heroku Dyno has 512Mb of Memory, so make sure your combined workers do not exceed that maximum amount, or your dyno will be shut down.


On the right hand side of that same tab you can see the number of dynos. Make sure it is the same as you set in worker_processes.



I ran several tests with ApacheBench to determine how much the performance improved. I ran 1000 Requests with 100 concurrent connections against the landing page of our staging application. The following graph shows the time the requests took combined with 1-4 workers. Going from one process to several increases performance drastically, from then on it is still a boost to your application, but not as drastically. However you have to find the right spot on how many workers you want unicorn to fork depending on your application. Having too many may shut down your dyno due to memory constraints.


So in closing using Unicorn as your Heroku Webserver not only pays off, but should be put into the Heroku documentation at least as advanced information. I actually talked to people and showed them our Unicorn setup, which convinced them that Heroku is not as expensive as it seems and especially when starting your project is a very viable alternative to having your own Server.

With every new dyno you get several more concurrent requests, which is pretty neat. If you have any questions regarding the setup or anything else you can send an email to  flo@codeship.io or tweet to @Codeship.

Sign up for a free Codeship Account


This post is very much built on Michael van Rooijen’s Blogpost. Gists that helped with the setup were by leshill and jamiew

Posts you may also find interesting:

Subscribe via Email

Over 60,000 people from companies like Netflix, Apple, Spotify and O'Reilly are reading our articles.
Subscribe to receive a weekly newsletter with articles around Continuous Integration, Docker, and software development best practices.

We promise that we won't spam you. You can unsubscribe any time.

Join the Discussion

Leave us some comments on what you think about this topic or if you like to add something.

  • Woni Telluh

    Your point #4 says: “Set the default Logger in application.rb (and not just production.rb) to STDOUT, otherwise logging doesn’t work. Thx to @krainboltgreene for mentioning that just setting this in production.rb is not enough.”

    But it does not say why “not just production.rb”. Do you know by any chance why setting this in production.rb is insufficient?

    For instance, this article – http://help.papertrailapp.com/kb/configuration/unicorn – which Heroku Support refers people to, does not mention application.rb, rather <environment>.rb.


    • Sorry for the late reply. The problem was simply that we didn’t get sufficient log output in development and test then

  • Pingback: Procfile, Foreman and Unicorn | Christopher Concepcion()

  • Chase Tran

    Excuse my lack of knowledge, how does a thin server work on Heroku compared to unicorn?

  • Pingback: Rails Tutorial: Setting Up a Server on Heroku for Free!Blog de Code()

  • Grace Gimon

    I have a problem setting up this configuration, the worker_processes value is 2 but in New Relic it shows 10 instances running ( See that I have 2 web dynos and 1 worker).

    If you have any idea why would this be happening, it would be great, thanks.

    • 2 worker_processes x 2 dynos + a Heroku worker should be 5. Could you check in your logs when you restart the dynos it should show you the number of workers it uses.

      • I have similar problem.
        I set up this on unicorn.rb :
        worker_processes Integer(ENV[“WEB_CONCURRENCY”] || 2)

        with 1 dyno (1GB RAM), no worker.

        but instances running in New relic sometimes shows 5 instances running!
        In average it shows 2 intances running which is correct.

  • Matt

    Major flaw to this setup – Why is the worker killed on deployment? shouldn’t background tasks continue to run on worker till task is finished, then deploy? It seems this would be a common scenario with continuously deploying code, but the long-running worker tasks like imports and jobs that require a few minutes or more are killed.

    • Do you mean the Unicorn or a Heroku Worker? Heroku automatically kills workers if they don’t respond after a few seconds to a kill request. That’s a limit of the Heroku platform you have to deal with

  • Adam

    I tried experimenting with Heroku, but found it was faster abd more reliable to put hundread dollar bills through a paper shredder.

  • or you can move your application to the PaaS hosting which is faster out-of-the-box (https://shellycloud.com/blog/2013/05/is-shelly-cloud-faster-than-heroku) ;).