Flask Configuration
When building Flask applications, proper configuration management is essential for creating maintainable, secure, and environment-adaptable web applications. This guide will walk you through the various ways to configure your Flask applications, from simple in-code settings to sophisticated environment-based configurations.
Introduction to Flask Configuration
Configuration in Flask refers to the various settings that determine how your application behaves. These settings might include database URIs, secret keys, debugging flags, and other application-specific parameters. Flask provides flexible ways to manage these settings across different environments (development, testing, production).
Why Configuration Matters
- Security: Properly configured applications keep sensitive information (like API keys) out of your code
- Environment adaptability: Your app can behave differently in development vs. production
- Maintainability: Centralized configuration makes it easier to update settings
- Testability: Proper configuration makes testing easier with separate test settings
Basic Configuration Methods
1. Direct Configuration
The simplest way to configure Flask is by setting configuration values directly on your app's config
dictionary:
from flask import Flask
app = Flask(__name__)
# Configuration directly on the app
app.config['DEBUG'] = True
app.config['SECRET_KEY'] = 'your-secret-key'
app.config['DATABASE_URI'] = 'sqlite:///app.db'
@app.route('/')
def hello():
return "Hello, Flask!"
if __name__ == '__main__':
app.run()
This approach works for simple applications but doesn't scale well for larger projects.
2. Using Configuration Files
For more complex applications, you can keep your configuration in separate Python files:
# config.py
DEBUG = True
SECRET_KEY = 'your-secret-key'
DATABASE_URI = 'sqlite:///app.db'
Then import and use it in your app:
from flask import Flask
app = Flask(__name__)
app.config.from_object('config')
@app.route('/')
def hello():
return f"Database: {app.config['DATABASE_URI']}"
if __name__ == '__main__':
app.run()
3. Class-Based Configuration
A more structured approach uses classes for different environments:
# config.py
class Config:
DEBUG = False
TESTING = False
SECRET_KEY = 'your-secret-key'
DATABASE_URI = 'sqlite:///production.db'
class DevelopmentConfig(Config):
DEBUG = True
DATABASE_URI = 'sqlite:///development.db'
class TestingConfig(Config):
TESTING = True
DATABASE_URI = 'sqlite:///testing.db'
class ProductionConfig(Config):
# Production-specific settings
DATABASE_URI = 'sqlite:///production.db'
Using the configuration in your app:
from flask import Flask
import config
app = Flask(__name__)
# Choose the right configuration based on environment
app.config.from_object(config.DevelopmentConfig)
@app.route('/')
def hello():
if app.config['DEBUG']:
return f"Running in DEBUG mode with database: {app.config['DATABASE_URI']}"
return "Production mode"
if __name__ == '__main__':
app.run()
Environment Variables and Security
Hardcoding sensitive information like secret keys and database credentials in your code is a security risk. Using environment variables is a safer approach:
# config.py
import os
class Config:
SECRET_KEY = os.environ.get('SECRET_KEY', 'fallback-key-for-development')
DATABASE_URI = os.environ.get('DATABASE_URI', 'sqlite:///app.db')
DEBUG = os.environ.get('FLASK_DEBUG', '0') == '1'
To set these environment variables:
On Linux/Mac:
export SECRET_KEY="my-super-secret-key"
export DATABASE_URI="sqlite:///production.db"
export FLASK_DEBUG=0
python app.py
On Windows:
set SECRET_KEY=my-super-secret-key
set DATABASE_URI=sqlite:///production.db
set FLASK_DEBUG=0
python app.py
Configuration Best Practices
1. Using the python-dotenv Package
For easier environment variable management, use the python-dotenv
package:
pip install python-dotenv
Create a .env
file in your project root:
# .env file
SECRET_KEY=my-super-secret-key
DATABASE_URI=sqlite:///dev.db
FLASK_DEBUG=1
Then load these variables in your app:
from flask import Flask
from dotenv import load_dotenv
import os
# Load environment variables from .env file
load_dotenv()
app = Flask(__name__)
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')
app.config['DATABASE_URI'] = os.environ.get('DATABASE_URI')
app.config['DEBUG'] = os.environ.get('FLASK_DEBUG') == '1'
@app.route('/')
def hello():
return f"Using database: {app.config['DATABASE_URI']}"
if __name__ == '__main__':
app.run()
Never commit your .env
file to version control! Add it to your .gitignore
file.
2. Configuration from JSON Files
Flask also supports loading configuration from JSON files:
import json
from flask import Flask
app = Flask(__name__)
app.config.from_file('config.json', load=json.load)
@app.route('/')
def hello():
return f"App name: {app.config.get('APP_NAME', 'Flask App')}"
if __name__ == '__main__':
app.run()
With a config.json
file:
{
"APP_NAME": "My Flask Application",
"SECRET_KEY": "json-config-secret-key",
"DEBUG": true
}
Accessing Configuration Values
Once configured, you can access configuration values from anywhere in your application:
from flask import Flask, current_app
app = Flask(__name__)
app.config['APP_NAME'] = 'Configuration Demo'
@app.route('/')
def hello():
# Access through app.config
return f"Welcome to {app.config['APP_NAME']}"
@app.route('/debug')
def debug_status():
# Access through current_app when outside app context
if current_app.config.get('DEBUG'):
return "Debugging is enabled."
return "Debugging is disabled."
if __name__ == '__main__':
app.run(debug=True)
Real-World Example: Complete Configuration System
Here's a more complete example showing a production-ready configuration system:
# app_structure/
# ├── app/
# │ ├── __init__.py
# │ └── routes.py
# ├── config.py
# ├── .env
# └── run.py
# config.py
import os
from dotenv import load_dotenv
# Load environment variables
load_dotenv()
class Config:
"""Base config class"""
APP_NAME = "Flask App"
SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-key-please-change')
SQLALCHEMY_TRACK_MODIFICATIONS = False
class DevelopmentConfig(Config):
"""Development configuration"""
DEBUG = True
SQLALCHEMY_DATABASE_URI = os.environ.get('DEV_DATABASE_URI') or \
'sqlite:///dev.db'
class TestingConfig(Config):
"""Testing configuration"""
TESTING = True
SQLALCHEMY_DATABASE_URI = os.environ.get('TEST_DATABASE_URI') or \
'sqlite:///test.db'
class ProductionConfig(Config):
"""Production configuration"""
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URI') or \
'sqlite:///prod.db'
# Dictionary to easily select the environment
config_dict = {
'development': DevelopmentConfig,
'testing': TestingConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
# app/__init__.py
from flask import Flask
from config import config_dict
import os
def create_app(config_mode='default'):
"""Create and configure the Flask app"""
app = Flask(__name__)
# Get configuration from environment or use default
env_config = os.environ.get('FLASK_CONFIG', config_mode)
app.config.from_object(config_dict[env_config])
# Initialize extensions here
# db.init_app(app)
# migrate.init_app(app, db)
# Register blueprints
from app.routes import main_blueprint
app.register_blueprint(main_blueprint)
return app
# app/routes.py
from flask import Blueprint, current_app
main_blueprint = Blueprint('main', __name__)
@main_blueprint.route('/')
def index():
app_name = current_app.config.get('APP_NAME')
environment = 'Development' if current_app.debug else 'Production'
return f"Welcome to {app_name}! Running in {environment} mode."
# run.py
from app import create_app
app = create_app()
if __name__ == '__main__':
app.run()
And a sample .env
file:
SECRET_KEY=my-super-secret-production-key
FLASK_CONFIG=development
DEV_DATABASE_URI=sqlite:///instance/dev.db
DATABASE_URI=sqlite:///instance/prod.db
Flask's Built-in Configuration Values
Flask has several built-in configuration values with specific meanings:
Configuration Key | Default | Description |
---|---|---|
DEBUG | False | Enables debug mode |
TESTING | False | Enables testing mode |
SECRET_KEY | None | Secret key for session security |
PERMANENT_SESSION_LIFETIME | timedelta(days=31) | Lifetime of a permanent session |
JSON_AS_ASCII | True | Serialize objects to ASCII-encoded JSON |
TEMPLATES_AUTO_RELOAD | None | Reload templates when they change |
Summary
Proper configuration management is crucial for building robust Flask applications. In this guide, we've covered:
- Basic configuration using the app.config dictionary
- File-based configuration with Python modules
- Class-based configuration for different environments
- Using environment variables for sensitive information
- Best practices for secure configuration management
- Accessing configuration values throughout your app
- A complete real-world configuration system
By implementing these patterns, you can create Flask applications that are secure, easily configurable, and adaptable to different environments.
Exercises
- Create a simple Flask application with different configurations for development and production environments.
- Implement a configuration system that uses environment variables for sensitive information.
- Create a Flask app that displays different information based on its configuration settings.
- Build a configuration system that automatically selects the right configuration based on an environment variable.
- Implement configuration for a Flask application with database connections that change based on the environment.
Additional Resources
- Official Flask Configuration Documentation
- Python dotenv documentation
- Twelve-Factor App: Config - Best practices for configuration in modern applications
- Flask Mega-Tutorial: Configuration
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)