Configuration

Scaffolded apps load settings in app/config/Settings.py and build the connection map in app/config/Database.py. Pass DATABASES into Future(config=...) in run.py.

Option A — .env + python-dotenv (scaffold default)

future init creates .env.example. Copy it and edit:

cp .env.example .env
APP_NAME=Future
APP_DOMAIN=
APP_HOST=127.0.0.1
APP_PORT=8000
APP_DEBUG=True
APP_WORKERS=1
DB_DATABASE=database

app/config/Settings.py (generated):

from os import environ as env
from dotenv import load_dotenv

load_dotenv(dotenv_path=".env")

APP_NAME = str(env.get("APP_NAME", "Future"))
APP_DEBUG = env.get("APP_DEBUG", "False").lower() == "true"
APP_HOST = str(env.get("APP_HOST", "127.0.0.1"))
APP_PORT = int(env.get("APP_PORT", 8000))
APP_WORKERS = int(env.get("APP_WORKERS", 1))
APP_DOMAIN = str(env.get("APP_DOMAIN", ""))

DB_DATABASE = str(env.get("DB_DATABASE", "database"))

SQLite opens {DB_DATABASE}.sqlite (e.g. databasedatabase.sqlite).

Option B — YAML + Ansible Vault

Same idea: load a file once in Settings.py, export module-level constants. Useful when secrets are vault-encrypted:

# environment.yml
app_name: "myapp"
app_domain: "example.com"
app_host: "127.0.0.1"
app_port: 5000
app_workers: 1
app_debug: true
sqlite_database: "myapp"
# secret_token: !vault |
#   $ANSIBLE_VAULT;1.1;AES256
#   ...
# app/config/Settings.py — sketch
from ansible.parsing.dataloader import DataLoader
from ansible.parsing.vault import VaultSecret, VaultSecretsContext
from ansible.module_utils.common.text.converters import to_bytes
from ansible.constants import DEFAULT_VAULT_ID_MATCH

def load_environment_config(path: str) -> dict:
    vault_pass = "..."  # or getpass()
    loader = DataLoader()
    secrets = [(DEFAULT_VAULT_ID_MATCH, VaultSecret(to_bytes(vault_pass)))]
    loader.set_vault_secrets(vault_secrets=secrets)
    VaultSecretsContext.initialize(VaultSecretsContext(secrets))
    data = loader.load_from_file(file_name=path)
    return {key: value if isinstance(value, (bool, int)) else str(value) for key, value in data.items()}

config = load_environment_config("./environment.yml")
APP_NAME = str(config["app_name"])
APP_DOMAIN = str(config["app_domain"])
APP_HOST = str(config["app_host"])
APP_PORT = int(config["app_port"])
APP_DEBUG = config["app_debug"]
APP_WORKERS = int(config["app_workers"])
SQLITE_DATABASE = str(config["sqlite_database"])

Encrypt a string into the file:

ansible-vault encrypt_string 'mytoken' --name 'secret_token' --ask-vault-pass >> environment.yml

Pick one loader for the app (dotenv or YAML). Controllers and Database.py only import the constants.

Database map

app/config/Database.py is data only — no Connections call at import:

from future.databases.SQLite import SQLite
from app.config.Settings import DB_DATABASE

DATABASES = {
    "default": "sqlite",
    "sqlite": SQLite(database=DB_DATABASE),
}

Multi-driver example (same pattern — values from Settings):

from future.databases.SQLite import SQLite
from future.databases.MySQL import MySQL
from future.databases.Postgres import Postgres
# ...
DATABASES = {
    "default": "sqlite",
    "sqlite": SQLite(database=SQLITE_DATABASE),
    "mysql": MySQL(host=MYSQL_HOST, port=MYSQL_PORT, username=MYSQL_USERNAME, password=MYSQL_PASSWORD, database=MYSQL_DATABASE),
    "postgres": Postgres(host=POSTGRES_HOST, port=POSTGRES_PORT, username=POSTGRES_USERNAME, password=POSTGRES_PASSWORD, database=POSTGRES_DATABASE),
}

Wire it in run.py:

config = {
    "APP_DOMAIN": APP_DOMAIN,
    "APP_NAME": APP_NAME,
    "DATABASES": DATABASES,
}
app = Future(lifespan=lifespan, config=config)

Config keys the core uses

Key Role
APP_DOMAIN Host/subdomain routing; "" = domainless
APP_NAME Banner / OpenAPI title fallback
APP_DEBUG Uvicorn reload; log level
DATABASES Connection registry at boot
OPENAPI Docs enablement and UIs
GRAPHQL_SCHEMA Optional Strawberry schema for GraphQLController
APP_ASGI Import string for reload / multi-worker (default run:app)