Configuration Management
Flask provides a flexible configuration system through the Config class, which is a specialized dictionary subclass. This system allows you to load settings from multiple sources, including Python modules, files, and environment variables, while maintaining a clear separation between code and configuration.
The Uppercase Rule
A defining characteristic of Flask's configuration loading is that it primarily processes keys that are fully uppercase. This allows you to use lowercase variables in your configuration files or modules for temporary calculations or internal logic without them being added to the application's configuration object.
# config.py
DEBUG = True
SECRET_KEY = "secret"
internal_value = "this will be ignored"
When you load this file using app.config.from_pyfile("config.py"), only DEBUG and SECRET_KEY will be available in app.config. This rule is enforced by methods like from_pyfile, from_object, and from_mapping.
Loading Configuration Sources
Flask provides several methods on the app.config object to populate settings from different environments.
Dictionaries and Mappings
Use from_mapping to set multiple values at once. This is frequently used in application factories to set default values.
def create_app(test_config=None):
app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY="dev",
DATABASE=os.path.join(app.instance_path, "flaskr.sqlite"),
)
if test_config:
app.config.from_mapping(test_config)
return app
Python Files and Modules
The from_pyfile method loads configuration from an external Python file. This is ideal for deployment-specific settings that should not be committed to version control.
app.config.from_pyfile("config.py", silent=True)
Alternatively, from_object can load configuration from a Python object, such as a class or a module. This is useful for managing different configuration tiers (e.g., Development vs. Production).
class Config:
TESTING = False
DEBUG = False
class ProductionConfig(Config):
DATABASE_URI = "mysql://user@localhost/foo"
class DevelopmentConfig(Config):
DEBUG = True
app.config.from_object(DevelopmentConfig)
Environment Variables
For modern, containerized applications, from_prefixed_env is the recommended way to load configuration from environment variables. By default, it looks for variables starting with FLASK_.
# If FLASK_DEBUG=true is set in the environment
app.config.from_prefixed_env()
assert app.config["DEBUG"] is True
This method automatically attempts to parse values as JSON (using json.loads), allowing you to set booleans, integers, and even lists or dictionaries. It also supports nested dictionaries using a double underscore (__) as a separator:
export FLASK_DATABASE__HOST=localhost
export FLASK_DATABASE__PORT=5432
This results in app.config["DATABASE"] being {"HOST": "localhost", "PORT": 5432}.
If you need to point to a specific configuration file via an environment variable, use from_envvar:
# Loads the file pointed to by the MYAPP_SETTINGS environment variable
app.config.from_envvar("MYAPP_SETTINGS")
JSON and TOML Files
The from_file method allows loading from other formats by providing a loader function.
import json
app.config.from_file("config.json", load=json.load)
import tomllib
app.config.from_file("config.toml", load=tomllib.load, text=False)
The Instance Folder
Flask supports an "instance folder" for deployment-specific files. When you create your app with instance_relative_config=True, relative paths passed to configuration loading methods are resolved relative to this folder instead of the application root.
# The app will look for 'config.py' in the instance folder
app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile("config.py")
The instance folder is typically located at /path/to/app/instance. You can find its exact path via app.instance_path.
Accessing Configuration
Configuration values can be accessed directly from the app.config dictionary:
db_uri = app.config["DATABASE_URI"]
In Jinja2 templates, the config object is available globally:
<p>The secret key is: {{ config['SECRET_KEY'] }}</p>
Config Attributes
Flask provides ConfigAttribute descriptors on the Flask class that map specific attributes directly to configuration keys. For example, app.debug is a shortcut for app.config["DEBUG"].
In src/flask/sansio/app.py, these are defined as:
testing = ConfigAttribute[bool]("TESTING")
secret_key = ConfigAttribute[str | bytes | None]("SECRET_KEY")
permanent_session_lifetime = ConfigAttribute[timedelta](
"PERMANENT_SESSION_LIFETIME",
get_converter=_make_timedelta,
)
Setting app.secret_key = "new-key" is equivalent to setting app.config["SECRET_KEY"] = "new-key".
Namespaced Configuration
If you have several related configuration keys, you can extract them into a separate dictionary using get_namespace. This is often used when passing settings to third-party libraries or extension constructors.
app.config["IMAGE_STORE_TYPE"] = "fs"
app.config["IMAGE_STORE_PATH"] = "/var/app/images"
# Returns {'type': 'fs', 'path': '/var/app/images'}
image_config = app.config.get_namespace("IMAGE_STORE_")
Internal Implementation
The Config class (defined in src/flask/config.py) inherits from dict. When a Flask application is initialized, it calls make_config (in src/flask/sansio/app.py), which populates the configuration with defaults from Flask.default_config.
# src/flask/app.py
default_config = ImmutableDict(
{
"DEBUG": None,
"TESTING": False,
"SECRET_KEY": None,
"PERMANENT_SESSION_LIFETIME": timedelta(days=31),
"APPLICATION_ROOT": "/",
# ...
}
)
The Config object also tracks the root_path, which it uses to resolve relative filenames when loading from files.