Heroku¶
Heroku is an app hosting platform that supports multiple programming languages, including python. To get the most out of it, you'll need to develop a user interface for your app with a package like streamlit
, dash
, django
or flask
. Anything that renders your application in HTML will suffice.
Heroku loads all of the software (i.e., python, the packages you need, and your scripts) into a container on its servers in what they call a 'dyno'. That way, your users can run the software without having to load it on their own machine. Heroku is similar to Shiny Apps, if you're used to the R ecosystem.
It's also worth noting that Heroku does not store data for you. In other words, you won't be able to access the .csv
files or .png
files you have been passing to your program. You'll need to find a cloud-based hosting service like Google Drive or Amazon S3 for those assets.
Tutorial¶
This tutorial will walk you through the process of deploying a streamlit
app on Heroku. You'll need to set up a virtual environment, understand the basics of git, and be comfortable working from the command line. You should also review the Google API tutorial to set up Google Sheets as a back-end.
Step-by-step¶
-
Create a new project folder
-
Open an Anaconda Prompt window within the project folder
-
Initialize git (
git init
) -
Create a
.gitignore
file (code .gitignore
) -
Add (one per line):
*.pyc
,secrets/
, and any other files or folders you want ignored (e.g.,notebooks/
,data/
if you have will be working in jupyter notebooks or with local data while you build your app) -
Create a virtual environment (
conda create -n <project-name> python
) -
Activate the environment (
conda activate <project-name>
) -
Install any packages you'll need using the
conda
package manager -
Build your project locally, working within the project's environment
-
Create a
requirements.txt
file. To do this, you will first need to installpip
into your environment (install pip
). Then use the commandpip freeze > requirements.txt
. As an alternative, you can simply list the top-level libraries you are using (i.e., the packages you import in your script). If, when deploying to Heroku, you get an error that a package cannot be found, delete that package fromrequirements.txt
. I've found fewer issues with just listing top-level libraries, but you risk version issues cropping up later. -
Optionally, create a
runtime.txt
file to tell Heroku which python version to install. Only certain versions are supported by Heroku, so check the documentation first. Use the commandpython -V > runtime.txt
, or type in the python version you'd prefer Heroku install. -
Create a Procfile, which tells Heroku how to actually run your app. The Procfile is run when the app is initialized in each session. Type
code Profile
to create a new file and add the command Heroku will use to run your app. It's different for each technology, but for a streamlit app the text issh setup.sh && streamlit run <my_app.py>
. The app will run from the root folder, so make sure if your script is stored in a folder, you include it in the path (e.g,sh setup && streamlit run <scripts/my_app.py>
). Also, make sure that the relative paths in your script are relative to the root folder, NOT the script itself. -
For a
streamlit
app, you'll need to create asetup.sh
file. Create a new filecode setup.sh
and paste the below into it (note language is bash):
mkdir -p ~/.streamlit/
echo "\
[general]\n\
email = \"your-email@domain.com\"\n\
" > ~/.streamlit/credentials.toml
echo "\
[server]\n\
headless = true\n\
enableCORS=false\n\
port = $PORT\n\
" > ~/.streamlit/config.toml
-
Create a Procfile for local development, if needed:
code Procfile.windows
web: streamlit run scripts/<my_app.py> runserver 0.0.0.0:5000
-
Commit changes to git (
git add .
,git commit -m "message"
) -
Create the Heroku app:
heroku create <app name>
where<app name>
will serve as the base of the url and the name of the app on Heroku's dashboard -
Deploy the code to Heroku:
git push heroku master
-
Spin up one dyno:
heroku ps:scale web=1
(useheroku ps:scale web=0
) to shut it down. Useheroku ps
to see how many dynos are running. -
Open the app:
heroku open
. -
If the app isn't up yet, or something looks wrong, check the logs with
heroku logs --tail
. You can close the logs withctrl+c
. -
If you need to run the app locally, you can use the command
heroku local web -f Procfile.windows
. -
If you make changes to the app, commit everything to git and then push it back up to Heroku. Every time you push to Heroku, it rebuilds the dyno from scratch, which can take some time depending on how many packages you need to load, so try to do that sparingly.
-
If you have API tokens or other sensitive information, you'll need to configure Heroku's configuration variables. This is equivalent to setting an environment variable on your local machine. These variables will only be exposed at runtime, and won't be accessible to your users. Simply type
heroku config:set <VAR_NAME> = <VAR_VALUE>
. For JSON blobs, it's easiest to add them through Heroku's online interface (under the 'Settings' of the app.) You can paste in the prettified JSON as a new variable there. See the Google API page for more info on accessing those variables within your scripts.
Your app should now be up and running on Heroku. If you're on a free tier, it may take 10-20 seconds for the app to load each time because the server needs to spin it up. It will be active for 30 minutes, but will sleep again after that time. You can upgrade to a Hobby license for $7 per dyno per month.
Update an existing app¶
Updating an existing app is as simple as running git push heroku master
from the project's root directory. However, if you have cloned the repository (or you, say, deployed it last time from a different computer), you'll need to establish the remote connection with heroku first.
Type heroku login
to login (a browser window will open) and then heroku git:remote -a <app-name>
to connect to the app. The <app-name>
can be found on your heroku page.
Notes¶
Note that in recent updates the setup.sh may not be required, instead you can use this command in the Procfile:
web: streamlit run --server.enableCORS false my_script.py
(but I haven't tested it).