Django/Heroku quickstart for existing applications

Getting a brand new Django application running on Heroku is fairly simple. There is a great tutorial for it on I would recommend going through that, and getting it working. Here is my short version of their getting started notes, without the virtualenv and Django command stuff you probably already know.

wget -qO- | sh
heroku login
heroku create --stack cedar
echo 'web: python runserver 0:$PORT' > Procfile
heroku addons:add shared-database
git push heroku master  # if you're in a branch locally, you can git push -f heroku localbranch:refs/heads/master
heroku run python syncdb
heroku ps:scale web=1
heroku ps
heroku logs

That should be enough to get a brand new Django app running. If you have an existing Django application, however, their documentation doesn't provide much guidance on common pitfalls.

First of all, you may need a mechanism to over-ride on the production Heroku instance. First, you can add an environment variable:

heroku config:add ENVIRONMENT=production

With that variable, you can easily create an over-ride for called

# at the END of
import os
ENVIRONMENT = os.environ.get('ENVIRONMENT', 'dev')  # dev, production, qa, etc
exec('from settings_%s import *' % ENVIRONMENT)

Heroku gives you a shared database for free. You can see the connect string on it with the heroku config command:

DATABASE_URL => postgres://

This would translate into the following in

    'default': {
        'ENGINE': 'postgresql_psycopg2',
        'NAME': 'instance',
        'USER': 'foobar',
        'PASSWORD': 'password',
        'HOST': '',
        'PORT': '',  # leave blank

The Heroku directions for switching from Django's development web server to gunicorn don't work for Django 1.3, where there is no WSGI file. After adding gunicorn to requirements.txt, and 'gunicorn' to INSTALLED_APPS, I changed Procfile to the following:

web: python run_gunicorn -b$PORT

Getting Django's staticfiles feature working was a little trickier. Heroku gives you a "ephemeral" file system, meaning that any changes you write to disk will not survive the next deploy, and may not even survive between heroku command-line sessions. This means that collectstatic must be run as part of the deploy, which you can also do in Profile:

web: python collectstatic --noinput; python run_gunicorn -b$PORT

Lastly, I wanted gunicorn to (at least temporarily) serve up the static resources itself. To do that, you will need to add the following to your

urlpatterns += patterns('',
    (r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.STATIC_ROOT}),

Heroku gives you SSL for free, at least when you're on * The only tricky bit is that you need to tell Django which header to look at to determine if the original request was in SSL (Heroku will only speak plain HTTP to Django). Without this, any redirect from an HTTPS URL will direct the user back to HTTP. Just put the following in


Finally, I had to migrate my old data. If you're going from Postgres -> Postres, or MySQL -> MySQL, just use the herokup database restore tools. If you need to migrate from one to the other, things get a lot trickier. In my case, I ended up exporting to a JSON file, and re-importing. This was very buggy; I would not recommend it.

I'm currently working at NerdWallet, a startup in San Francisco trying to bring clarity to all of life's financial decisions. We're hiring like crazy. Hit me up on Twitter, I would love to talk.

Follow @chase_seibert on Twitter