I’ve built a few applications using Flask, but I’ve had trouble handling configuration, especially when it comes to handling different environments.
But I’ve found a way that works, is simple, and is easy even when using multiple environments. I’ll share the details below, or you can go view it on Gist.
The Problem
As mentioned, the main issue I’d had was with switching between different environments (production, development, testing). For instance, in each environment, I’d need to specify the URL of a different database to use.
In previous applications, I would handle this issue by using different configuration files for each environment, and switch the file depending on the environment I was working with.
I didn’t like this approach for 2 reasons:
- It was open to user error (what if I forgot to switch settings files and launched to production)
- It seemed like more work than was necessary (overly complex)
So I went seeking for a solution.
The Flask documentation presents a few ways to handle configuration, but I wasn’t thrilled with their options. They either required too much input from a user (open to human error) or were a bit too complex (I wanted to make this as simple as possible).
But I did see a line in the documentation which stated: “Use an environment variable to switch between the configurations.”
Going with this idea and combining it with some of the example configurations, I came up with an elegant solution.
The Solution
The basic idea is to set all configurations within one configuration file. Then the user can set an environment variable which Flask can use to tell which environment it is in. Switching environments just requires changing that environment variable.
I liked this approach because it required only one action of the user (setting an environment variable) and abstracted the complexity away (no more need for multiple configuration files). I also can easily use the same code in each environment (no more multiple repos).
Here is the code I ended up with:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import os | |
# Get environment, or set to development by default | |
app_env = os.environ.get('APPLICATION_ENVIRONMENT') or 'development' | |
# Settings applied to all environments | |
SECRET_KEY = 'development key' | |
# Settings applied to specific environments | |
if app_env == 'production': | |
DATABASE_URI = '' # TODO: Enter your production database | |
DEBUG = False | |
elif app_env == 'development': | |
DATABASE_URI = '' # TODO: Enter your dev database | |
DEBUG = True | |
elif app_env == 'testing': | |
DATABASE_URI = '' # TODO: Enter your test database |
So what’s going on here?
We are first reading the environment variable APPLICATION_ENVIRONMENT
. If there is none set, it defaults to 'development'
.
We can then set the configuration settings which are applicable to all environments (such as the SECRET_KEY
).
Then, we can override settings depending on the current environment, such as setting a different database for each environment.
How I Used This In My Workflow
I’ve been working on a bookmarking/link shortening application (https://github.com/byanofsky/bookmarks/) which I deployed to Heroku.
On the Heroku production server, I set the APPLICATION_ENVIRONMENT
to 'production'
.
On my local Vagrant server where I do development and testing, I easily switch between the two environments as needed.
I also created a fourth environment that I use for staging that connects with a staging server on Heroku and test with Heroku Local.
Switching between environments is easy, which makes managing my code simpler.
Last Thoughts
Hopefully this helps you with your Flask configuration handling.
If you find ways I can improve this, please let me know in the comments.
Thanks!