Skip to main content

Flask Environment Variables

When deploying Flask applications to production environments, managing configuration details like database credentials, API keys, and other sensitive information becomes crucial. Environment variables provide a secure and flexible way to handle these configurations across different deployment environments.

Introduction to Environment Variables in Flask

Environment variables are dynamic values that can affect the way running processes behave on a computer. In the context of Flask applications, they allow you to:

  • Store sensitive information outside your codebase
  • Change application behavior based on the environment (development, testing, production)
  • Follow security best practices by not hardcoding credentials
  • Configure your application without changing the source code

Why Use Environment Variables?

Consider this scenario: You've written a Flask application that connects to a database. During development, you might connect to a local database, but in production, you'll need to connect to a different server. Hardcoding these values makes your code less flexible and potentially exposes sensitive information if your code is shared or made public.

Bad practice (hardcoded credentials):

python
app.config['DATABASE_URI'] = 'postgresql://username:password@localhost/dev_db'
app.config['SECRET_KEY'] = 'my_super_secret_key'

Good practice (using environment variables):

python
import os

app.config['DATABASE_URI'] = os.environ.get('DATABASE_URI')
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')

Setting Up Environment Variables in Flask

The python-dotenv package allows you to set environment variables from a .env file, making development easier.

  1. Install the package:
bash
pip install python-dotenv
  1. Create a .env file in your project root:
# .env file
FLASK_APP=app.py
FLASK_ENV=development
SECRET_KEY=your_secret_key
DATABASE_URL=sqlite:///dev.db
API_KEY=your_api_key
  1. Load the environment variables in your Flask app:
python
from dotenv import load_dotenv
import os

load_dotenv() # Load environment variables from .env

app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
app.config['DATABASE_URL'] = os.environ.get('DATABASE_URL')

Method 2: Setting Environment Variables Directly

You can set environment variables directly in your terminal:

For Linux/macOS:

bash
export SECRET_KEY=your_secret_key
export DATABASE_URL=sqlite:///prod.db
python app.py

For Windows (Command Prompt):

cmd
set SECRET_KEY=your_secret_key
set DATABASE_URL=sqlite:///prod.db
python app.py

For Windows (PowerShell):

powershell
$env:SECRET_KEY = "your_secret_key"
$env:DATABASE_URL = "sqlite:///prod.db"
python app.py

Best Practices for Flask Environment Variables

1. Add .env to Your .gitignore File

To prevent accidentally committing sensitive information to your version control system:

# .gitignore
.env
.flaskenv

2. Provide Defaults for Non-Critical Variables

Always provide sensible defaults for non-critical environment variables:

python
debug_mode = os.environ.get('DEBUG', 'False').lower() in ['true', '1', 't']
app.debug = debug_mode

3. Create a Template .env File

Create a .env.example file that shows which environment variables your application needs, but without the actual sensitive values:

# .env.example
SECRET_KEY=your_secret_key_here
DATABASE_URL=your_database_url_here
API_KEY=your_api_key_here

4. Use Environment-Specific Configuration

Create configuration classes for different environments:

python
class Config:
"""Base config."""
SECRET_KEY = os.environ.get('SECRET_KEY', 'default-secret-key')

class DevelopmentConfig(Config):
FLASK_ENV = 'development'
DEBUG = True
DATABASE_URL = os.environ.get('DEV_DATABASE_URL')

class ProductionConfig(Config):
FLASK_ENV = 'production'
DEBUG = False
DATABASE_URL = os.environ.get('PROD_DATABASE_URL')

# Usage
config = ProductionConfig if os.environ.get('ENV') == 'production' else DevelopmentConfig
app.config.from_object(config)

Real-World Example: Configuring a Flask Application

Let's put everything together in a comprehensive example:

python
import os
from flask import Flask
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

# Create Flask application
app = Flask(__name__)

# Configure from environment variables
app.config.update(
SECRET_KEY=os.environ.get('SECRET_KEY', 'dev-key-for-development-only'),
DATABASE_URL=os.environ.get('DATABASE_URL', 'sqlite:///dev.db'),
DEBUG=os.environ.get('FLASK_DEBUG', 'False').lower() in ['true', '1', 't'],
MAIL_SERVER=os.environ.get('MAIL_SERVER', 'smtp.example.com'),
MAIL_PORT=int(os.environ.get('MAIL_PORT', 587)),
MAIL_USE_TLS=os.environ.get('MAIL_USE_TLS', 'True').lower() in ['true', '1', 't'],
MAIL_USERNAME=os.environ.get('MAIL_USERNAME'),
MAIL_PASSWORD=os.environ.get('MAIL_PASSWORD')
)

# Route demonstrating environment variable usage
@app.route('/')
def home():
env_name = os.environ.get('FLASK_ENV', 'development')
return f"Hello from {env_name} environment!"

# Route showing available configuration (be careful with this in production!)
@app.route('/config')
def show_config():
if app.debug:
# Only show config in debug mode
config_items = {key: str(value) for key, value in app.config.items()
if key not in ['SECRET_KEY', 'MAIL_PASSWORD']}
return f"<pre>{config_items}</pre>"
return "Configuration not available in production mode."

if __name__ == '__main__':
app.run(host='0.0.0.0', port=int(os.environ.get('PORT', 5000)))

Environment Variables in Production

In production environments, you'll typically set environment variables using your hosting platform's mechanisms:

Heroku

bash
heroku config:set SECRET_KEY=your_secret_key
heroku config:set DATABASE_URL=postgres://...

Docker

In your Dockerfile or docker-compose.yml file:

yaml
# docker-compose.yml
services:
web:
build: .
environment:
- SECRET_KEY=your_secret_key
- DATABASE_URL=postgres://...

AWS Elastic Beanstalk

You can set environment variables through the AWS Management Console or using the EB CLI:

bash
eb setenv SECRET_KEY=your_secret_key DATABASE_URL=postgres://...

Security Considerations

  1. Never store .env files in version control
  2. Use different keys for development and production
  3. Regularly rotate sensitive keys and credentials
  4. Limit access to production environment variables
  5. Consider using a secrets management service for production (like AWS Secrets Manager, HashiCorp Vault, etc.)

Summary

Environment variables are essential for secure and flexible Flask application deployment. They allow you to:

  • Keep sensitive information out of your codebase
  • Adapt your application to different environments
  • Follow security best practices
  • Configure your application without code changes

By adopting environment variables in your Flask applications, you're implementing a fundamental best practice that will make your applications more secure, maintainable, and deployment-ready.

Additional Resources

Exercises

  1. Create a Flask application that uses environment variables to configure a database connection.
  2. Set up different environment configurations (development, testing, production) using environment variables.
  3. Implement a mechanism that shows different error detail levels based on the environment.
  4. Create a Flask application that connects to an external API using an API key stored in an environment variable.

Remember, properly managing environment variables is a crucial step towards building production-ready Flask applications!



If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)