Python dash Application Boilerplate

Since I first started using dash in production environments, I have developed a recipe that allows for faster deployment that also scales well for different business needs. Let’s start by looking at the folder structure that I use:

repository-name/
    .gitignore
    LICENSE.txt
    assets/
        styles.css
        favicon.ico
    app.py
    gunicorn.conf.py
    Procfile
    requirements.txt

Let’s break down the contents of each file…

.gitignore

The stuff we don’t want in our repository. Instead of using Github’s boilerplate, I tend to keep the content very minimal.

venv
*.pyc
.DS_Store
.env
.cache/
__pycache__/
cache-directory/

requirements.txt

Contains the required dependencies and version criteria. Typically, this is generated from pip -m freeze > requirements.txt

app.py

This is your main Dash application. I tend to keep all dashboard elements in one file instead of having multiple imports.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from dash import html
from dash import dcc

from dash import Dash
from dash import Input
from dash import Output
from dash import State

app = Dash(__name__)
server = app.server

app.layout = html.Div(
    # layout elements go here
)

# application callbacks

if __name__ == __main__:
    app.run_server(debug=False)

Procfile

Contains a list of process types for an app. This is required for deployment platforms, such as Heroku. For my purposes, I typically specify Gunicorn, which is a WSGI HTTP server.

web: gunicorn -c gunicorn.conf.py app:server

gunicorn.conf.py

This is where I handle my server instantiation and configuration using Gunicorn.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import multiprocessing

chdir = /root
bind = :80
workers = multiprocessing.cpu_count() * 2 + 1
threads = multiprocessing.cpu_count() * 2 + 1
worker_connections = 1000 * workers
errorlog = /tmp/gunicorn.log
loglevel = warning

And that’s it! I hope someone just getting started with Dash applications found this helpful. If you have any feedback or suggestions on how I could improve this boilerplate further, feel free to email me!