Skip to content

Configuration

Fullfinity is configured via config.yaml in the project root. When running with Docker Compose, a config is auto-created with working defaults on first startup.

# config.yaml — Docker defaults (works out of the box)
WORKERS: 2
SERVER_PORT: 8000
DB_USERNAME: "fullfinity"
DB_PASSWORD: "fullfinity"
DB_HOST: "db" # "localhost" for native install
DB_PORT: "5432"
DB_POOL_MIN_CONNECTIONS: 5
DB_POOL_MAX_CONNECTIONS: 10
VALKEY_HOST: "cache" # "localhost" for native install
VALKEY_PORT: 6379
FILESTORE_PATH: "/app/filestore" # Local path for native install
SECRET_KEY: "change-me"
REFRESH_SECRET_KEY: "change-me"
ADDON_PATHS:
- "fullfinity/modules"
- "fullfinity/enterprise"
- "/app/addons" # a folder you mounted into the container
DB_USERNAME: "fullfinity"
DB_PASSWORD: "fullfinity"
DB_HOST: "db" # Docker service name, or "localhost" for native
DB_PORT: "5432"
DB_POOL_MIN_CONNECTIONS: 5 # Minimum connections kept in pool
DB_POOL_MAX_CONNECTIONS: 10 # Maximum concurrent connections

Control how users select and access databases.

SHOW_DBS: True # Enable database selector UI
DB_FILTER: None # No filter - all databases available

Controls whether users can access the database selector page (/web/database-selector).

ValueBehavior
TrueDatabase selector is accessible
FalseDatabase selector returns 404, auto-selects if only one DB matches

When SHOW_DBS: False and multiple databases match DB_FILTER, the server returns a 400 error.

A regex pattern to filter which databases are available. Supports hostname/subdomain placeholders for multi-tenant setups.

# No filter - all databases owned by DB_USERNAME are available
DB_FILTER: None
# Exact match
DB_FILTER: "^mycompany$"
# Prefix match
DB_FILTER: "prod_"
# Subdomain-based filtering (multi-tenant)
DB_FILTER: "^%s$"

Placeholders:

PlaceholderDescriptionExample
%sFirst subdomainacme from acme.example.com
%hFull hostnameacme.example.com
VALKEY_HOST: "cache" # Docker service name, or "localhost" for native
VALKEY_PORT: 6379
WORKERS: 2 # Number of Uvicorn workers
SERVER_PORT: 8000
LOG_LEVEL: "INFO" # DEBUG, INFO, WARNING, ERROR
LOG_CACHE_HITS: false # Log L2 cache hits (verbose, for debugging)
CRON_WORKERS: 1 # Background job workers (0 to disable)
SECRET_KEY: "your-secret-key-here"
REFRESH_SECRET_KEY: "your-refresh-secret-key"
ACCESS_TOKEN_EXPIRE_HOURS: 6
REFRESH_TOKEN_EXPIRE_DAYS: 14
FILESTORE_PATH: "/app/filestore" # Inside Docker
# FILESTORE_PATH: "/var/lib/fullfinity/filestore" # Native install
ADDON_PATHS:
- "fullfinity/modules" # Built-in modules (inside Docker image)
- "fullfinity/enterprise" # Licensed modules (gated at runtime)
- "/app/addons" # Your own modules (volume-mounted)

Every folder scanned for modules must be listed here — there is no magic default folder. Mount each of your addon folders into the container and add its in-container path as its own line. To load modules from several separate locations, mount each at a distinct /app/addons/<name> and add one line per folder.

For multi-tenant setups, combine SHOW_DBS and DB_FILTER:

SHOW_DBS: False
DB_FILTER: "^%s$"

This configuration:

  • Disables the database selector UI
  • Routes requests based on subdomain:
    • acme.example.comacme database
    • contoso.example.comcontoso database

Fullfinity supports AI-assisted translations for multi-language setups. Set one of:

OPENAI_API_KEY: "sk-..."
# or
ANTHROPIC_API_KEY: "sk-ant-..."

Browser web-push (VAPID) is off by default. Provide all three keys to enable it:

VAPID_PUBLIC_KEY: "B...." # served to the browser as applicationServerKey
VAPID_PRIVATE_KEY: "...." # signs each push (keep secret — use config.local.yaml)
VAPID_CONTACT_EMAIL: "ops@example.com" # becomes the VAPID "sub" claim (mailto:)
  • Generate a VAPID key pair once (e.g. with the py-vapid / web-push tooling) and reuse it; rotating the public key invalidates existing browser subscriptions.
  • No-op when unconfigured. If VAPID_PRIVATE_KEY or VAPID_CONTACT_EMAIL is missing, sending a push silently does nothing (it never raises). If VAPID_PUBLIC_KEY is missing, the frontend simply receives no key and won’t subscribe.
  • VAPID_PRIVATE_KEY is a secret — keep it in config.local.yaml, not in the committed config.yaml.

Local Overrides and Secrets (config.local.yaml)

Section titled “Local Overrides and Secrets (config.local.yaml)”

A sibling *.local.yaml file (e.g. config.local.yaml next to config.yaml), if present, is merged over the base config at the top level when the config is loaded. It is gitignored, so secrets — LICENSE_KEY, SECRET_KEY, REFRESH_SECRET_KEY, DB_PASSWORD, OPENAI_API_KEY, etc. — can live there instead of in the committed config.yaml. Keys in the local file override the base file.

# config.local.yaml (gitignored)
DB_PASSWORD: "real-password"
SECRET_KEY: "..."
REFRESH_SECRET_KEY: "..."
LICENSE_KEY: "..." # Enterprise SaaS license

Individual configuration keys are not overridable via environment variables — there is no FULLFINITY_-prefixed override mechanism for config values. Configuration comes only from config.yaml plus the optional config.local.yaml overlay. (The one environment variable the runtime reads is FULLFINITY_CONFIG_PATH, the path to the config file, which the CLI sets automatically from -c/--config so worker processes can find it.)

SettingDocker (default)Native install
DB_HOSTdblocalhost
VALKEY_HOSTcachelocalhost
FILESTORE_PATH/app/filestoreLocal path
ADDON_PATHSfullfinity/modules, fullfinity/enterprise, your mounted pathsfullfinity/modules, your paths