How to Deploy a Django App to Heroku: Step by Step Guide

Utku Burgaz
6 min readMay 7, 2022
Django Heroku Deployment
Image by author

I found myself writing this guide after struggling to deploy a prototype project to Heroku. After spending hours reading numerous blogs, manuals, tutorials and countless try and errors I finally glued essential bits and pieces together to make a guide.

Before continue further, I assume you’ve already have a Heroku user account. Additionally, have Python, Git and Heroku CLI installed in your computer.

Here is my 8 step recipe to deploy a Django project to Heroku.

Step 1- Create Virtual Environment

Let’s begin building our Django project with creating a project directory and a virtual environment in it.

$ mkdir DjangoProject
$ cd DjangoProject
$ python3 -m venv venv

Then activate your virtual environment with the following source command.

$ source venv/bin/activate
(venv) $

Notice that (venv) appears next to your username in the command line. Now you are in the environment and ready to install python packages with pip.

2- Install Django and Other Packages

Install following four python packages which lay the foundation of our Django project.

(venv) $ pip install django
(venv) $ pip install gunicorn
(venv) $ pip install django-on-heroku
(venv) $ pip install python-decouple

gunicorn is a Python HTTP server for WSGI applications. Later we will be using gunicorn while declaring a command in the Procfile.

django-on-heroku ensures seamless deployment for Heroku applications and also brings some very needed packages like dj-database-url and whitenoise so you don’t need to install them again.

python-decouple allows us to, as the name implies, decouple some sensitive information like the secret key, from project settings. In our case we will use it to separate local environment settings from deployed Heroku settings.

3- Create Django Project and Application

By using Django’s command line utility django-admin, start your Django project and app. A Django project refers to the entire application, whereas app refers to a submodule of the project.

(venv) $ django-admin startproject Mysite .
(venv) $ django-admin startapp blog

Now project directory and file structure looks like this:

.
├── Mysite
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── blog
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── migrations
│ ├── models.py
│ ├── tests.py
│ └── views.py
├── manage.py
└── venv
├── bin
├── include
├── lib
└── pyvenv.cfg

4- Configure Django Settings

To make our Django project up and running we need to make some configurations in settings.py and urls.py files and create a .env file to store local environment settings variables.

In setting.py file, we can retrieve the configuration parameters from .env by using config() object.

We basically need to add three host/domain names to ALLOWED_HOSTS list. ‘0.0.0.0’ and ‘127.0.0.1’ IP’s will be needed when we run the project locally. ‘.herokuapp.com’ is needed when we deploy the project to Heroku.

# settings.pyfrom decouple import config
from pathlib import Path
import dj_database_url
...SECRET_KEY = config('SECRET_KEY')

DEBUG = config('DEBUG', default=True, cast=bool)

ALLOWED_HOSTS = [
'.herokuapp.com',
'0.0.0.0',
'127.0.0.1',
]

As you create apps with django-admin startapp command, you should add them to INSTALLED_APPS list.

# settings.pyINSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#apps
'blog',
]

As I mentioned earlier, django-heroku brings whitenoise package together. whitenoise allows web server to serve its own static files. To activate the plugin add whitenoise to the MIDDLEWARE list.

# settings.pyMIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
# Simplified static file serving.
# https://warehouse.python.org/project/whitenoise/
'whitenoise.middleware.WhiteNoiseMiddleware',
]

Comment out the default DATABASES setting and add the following.

# settings.pyDATABASES = {}
DATABASES['default'] = dj_database_url.config(conn_max_age=600, ssl_require=True)
DATABASES['default'] = dj_database_url.config(default=config('DATABASE_URL'))

Change the static files section in settings.py as shown below.

# settings.pySTATIC_URL = 'static/'
STATIC_ROOT = BASE_DIR / 'staticfiles'
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'

Now create a .env file in the root of the project and add following settings.

# .env
SECRET_KEY=your-secret-key
DEBUG=True
DATABASE_URL=sqlite:///db.sqlite3

To set up static and media files serving during development, add the following to your urls.py file:

# urls.pyfrom django.conf import settings
from django.conf.urls.static import static
from django.contrib import admin
from django.urls import path
from django.views import debug
urlpatterns = [
path('', debug.default_urlconf),
path('admin/', admin.site.urls),
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)

5- Add Heroku Must Have Files

There are three must have files for a Heroku Python project:

  • Procfile
  • runtime.txt
  • requirements.txt

Heroku web applications need a Procfile. Be careful, Procfile has no file extension like .txt. Replace ‘Mysite’ with your Django project name.

# Procfileweb: gunicorn Mysite.wsgi

Create runtime.txt file to choose a python version, find Heroku supported runtimes here.

# runtime.txtpython-3.8.13

Generate an output file called requirements.txt for the list of installed packages. Heroku will use requirements.txt file to install your packages and resolve dependencies.

(venv) $ pip freeze > requirements.txt

Now go check the requirements.txt file.

# requirements.txtasgiref            3.6.0
backports.zoneinfo 0.2.1
dj-database-url 1.2.0
Django 4.1.7
django-on-heroku 1.1.2
gunicorn 20.1.0
psycopg2-binary 2.9.5
python-decouple 3.8
sqlparse 0.4.3
whitenoise 6.4.0

6- Setup Heroku and Configure Heroku Settings

I assume you’ve already signed up for a Heroku account. If not, go signup here.

After setting an account, you need to login by using Heroku CLI. This command will lead you to open browser to login.

(venv) $ heroku login

To create a new Heroku app with a random generated app name, like warm-ridge-01615 below, run the following command in Heroku CLI. You can always rename the app later.

(venv) $ heroku create
Creating app... done, ⬢ warm-ridge-01615
https://warm-ridge-01615.herokuapp.com/|https://git.heroku.com/warm-ridge-01615.git

We need a database, on Heroku we used to use free-tier PostgreSQL. But now the cheapest plan for Heroku Postgres is $5. It will be enough for a small project at a hobbiest level.

(venv) $ heroku addons:create heroku-postgresql:mini -a <YOUR-APP>

If you have multiple Heroku apps running at the same time you should clearly state the app name while adding an addon. Therefore add -a <YOUR-APP> at the end of the above command.

Now it’s time to configure project settings at Heroku. Optionally, you can manually set these settings in Settings tab at Heroku project dashboard.

(venv) $ heroku config:set SECRET_KEY=your-secret-key DEBUG=False

Remember, missing above step will lead an error while deploying your project.

Before deploying our project to Heroku, it is better to run the app locally via Heroku CLI to see if everything works well.

(venv) $ heroku local

Open http://localhost:5000 with your web browser, hopefully you will see the Django welcome page.

Django Welcome Page Screenshot
Image by author

7- Start a Git Repo

I hope everything did go well until here, not we are ready to deploy our project to Heroku!

But first, one last thing left to do 👀. Create .gitignore file at the root, listing untracked files. A comprehensive standard django .gitignore file can be found here. Mine is below:

# .gitignore# Django
*.pyc
staticfiles
db.sqlite3

# Environments
.env
venv/

Then, at the root, start a new repository, add project directory to repo, commit changes and push to upload local repository content to a remote Heroku repo.

(venv) $ git init
(venv) $ git add .
(venv) $ git commit -m ‘My first commit’
(venv) $ git push heroku master

8- Run the App on Heroku

And finally, open the app in a web browser with below command to check that everything is working 👏.

(venv) $ heroku open
Django Heroku Application Welcome Page Screenshot
Image by author

9- Bonus Step: Create Django Migrations and Admin User on Heroku

For sure, above steps does not include some important actions like reflecting changes in models to database, copying static files to the STATIC_ROOT folder and accessing Django admin panel.

The Great Wave off Kanagawa

By using run python command of Heroku CLI, run the following commands in order. After that, you should be able to login admin panel and access project models.

$ heroku run python manage.py collectstatic
$ heroku run python manage.py makemigrations
$ heroku run python manage.py migrate
$ heroku run python manage.py createsuperuser

That’s it! You’ve learned how to deploy a functioning Django application to Heroku.

--

--