Loading Configuration from Files and Objects
To populate application settings in this project, use the flask.config.Config object (available as app.config). This object is a dictionary subclass that provides specialized methods for loading configuration from Python files, objects, environment variables, and structured data formats like JSON or TOML.
A core convention in this project is the Uppercase Rule: most loading methods (except from_prefixed_env) only import keys that are fully uppercase. This allows you to use lowercase variables for internal logic within your configuration files without them being added to the application config.
Loading Defaults and Overriding with Files
The standard pattern for initializing configuration involves setting defaults in code and then overriding them with an external file, often located in an "instance folder" for environment-specific secrets.
import os
from flask import Flask
app = Flask(__name__, instance_relative_config=True)
# 1. Set defaults using from_mapping
app.config.from_mapping(
SECRET_KEY="dev",
DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
)
# 2. Override from a Python file in the instance folder
# Only uppercase variables in config.py will be loaded
app.config.from_pyfile("config.py", silent=True)
from_mapping: Updates the config like a standard dictionary but ignores non-uppercase keys.from_pyfile: Executes a Python file and loads its uppercase variables. Wheninstance_relative_config=Trueis passed to theFlaskconstructor, the path is relative to the application's instance folder.silent=True: Prevents the application from crashing if the configuration file is missing.
Loading from Python Objects or Modules
You can organize configurations into classes or modules and load them using from_object. This is useful for switching between "Development" and "Production" states.
class ProductionConfig:
DEBUG = False
TESTING = False
DATABASE_URI = 'mysql://user@localhost/foo'
# Load from the class reference
app.config.from_object(ProductionConfig)
# Or load from an import string
app.config.from_object('my_app.config.ProductionConfig')
- Import Strings: If you pass a string,
Configuseswerkzeug.utils.import_stringto locate and load the object. - Uppercase Only: Only attributes of the object that are uppercase are added to the config.
Loading from JSON or TOML Files
For structured data formats, use from_file. You must provide a loader function (like json.load or tomllib.load).
import json
import tomllib
# Load from a JSON file
app.config.from_file("config.json", load=json.load)
# Load from a TOML file (requires binary mode for tomllib)
app.config.from_file("config.toml", load=tomllib.load, text=False)
- Loader Function: The
loadparameter accepts any callable that takes a file handle and returns a mapping. - Uppercase Rule: Since
from_fileinternally callsfrom_mapping, only uppercase keys in the JSON/TOML file will be imported.
Loading from Environment Variables
This project provides two ways to load configuration from environment variables: pointing to a file or loading prefixed variables directly.
Loading via File Pointer
Use from_envvar to load configuration from a path stored in an environment variable.
# export APP_SETTINGS='/path/to/config.cfg'
app.config.from_envvar('APP_SETTINGS')
Loading Prefixed Variables
Use from_prefixed_env to load all environment variables starting with a specific prefix (default is FLASK_). This method supports nested dictionaries using double underscores (__).
# export FLASK_SECRET_KEY="secret"
# export FLASK_DATABASE__HOST="localhost"
# export FLASK_DATABASE__PORT=5432
app.config.from_prefixed_env()
# Resulting config:
# app.config['SECRET_KEY'] == "secret"
# app.config['DATABASE'] == {"HOST": "localhost", "PORT": 5432}
- Type Conversion: By default,
from_prefixed_envusesjson.loadsto attempt to convert string values to Python types (integers, booleans, dicts). If conversion fails, the value remains a string. - Nesting: Double underscores in the environment variable name are converted into nested dictionary keys.
Extracting Namespaced Configuration
If you have grouped settings (e.g., multiple settings for an image store), you can extract them into a separate dictionary using get_namespace.
app.config['IMAGE_STORE_TYPE'] = 'fs'
app.config['IMAGE_STORE_PATH'] = '/var/app/images'
# Extract settings starting with 'IMAGE_STORE_'
image_config = app.config.get_namespace('IMAGE_STORE_')
# Result: {'type': 'fs', 'path': '/var/app/images'}
lowercase=True: (Default) Converts the resulting keys to lowercase.trim_namespace=True: (Default) Removes the prefix from the resulting keys.
Troubleshooting
Dictionary vs. Object
A common mistake is trying to load a dictionary using from_object.
- Incorrect:
app.config.from_object({"DEBUG": True})— This will fail becausefrom_objectlooks for attributes viadir(), not dictionary keys. - Correct: Use
app.config.from_mapping({"DEBUG": True}).
Missing Keys
If a configuration value is not appearing in app.config after loading from a file or object, check the casing.
- Requirement: The key must be all uppercase (e.g.,
DEBUG, notDebugordebug). - Exception:
from_prefixed_envdoes not enforce the uppercase rule on the suffix after the prefix is removed, though uppercase is standard practice.
Environment Variable Types
When using from_prefixed_env, remember that values are parsed as JSON.
- To set a string that looks like a number, wrap it in quotes in your shell if necessary, or rely on the fact that if
json.loadsfails, it defaults to the raw string. - On Windows, environment variable keys are always uppercase, which may affect how
from_prefixed_envbehaves if you rely on specific casing for nested keys.