Skip to main content

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. When instance_relative_config=True is passed to the Flask constructor, 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, Config uses werkzeug.utils.import_string to 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 load parameter accepts any callable that takes a file handle and returns a mapping.
  • Uppercase Rule: Since from_file internally calls from_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_env uses json.loads to 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 because from_object looks for attributes via dir(), 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, not Debug or debug).
  • Exception: from_prefixed_env does 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.loads fails, it defaults to the raw string.
  • On Windows, environment variable keys are always uppercase, which may affect how from_prefixed_env behaves if you rely on specific casing for nested keys.