Settings
App-wide settings (FastPluggyConfig)
Stored in the database and editable in the admin UI at /admin/settings.
Values can also be set via environment variables (prefix: as configured by pydantic-settings).
| Key | Env var | Default | Description |
|---|---|---|---|
app_name |
APP_NAME |
"FastPluggy" |
Displayed in sidebar and topbar |
fp_admin_base_url |
FP_ADMIN_BASE_URL |
"/" |
Admin URL prefix |
debug |
DEBUG |
False |
Show tracebacks on error pages |
fp_plugins |
FP_PLUGINS |
"*" |
Comma-separated entry-point plugin names, or "*" for all |
show_empty_menu_entries |
— | False |
Show sidebar parents with no visible children |
admin_enabled |
— | True |
Mount the FastPluggy admin UI |
include_in_schema_fp |
— | False |
Include FastPluggy routes in OpenAPI schema |
Env-only settings (not admin-UI-editable)
These four are read directly from the environment before the database is even
probed, so the app-level middleware they configure (SessionMiddleware,
GZipMiddleware) can be installed once at boot — required for the
degraded-mode self-heal (fast_pluggy#22) to work at all, since a middleware
can never be added again once the app has served its first request. A value
saved for these via /admin/settings is silently never read.
| Key | Env var | Default | Description |
|---|---|---|---|
session_secret_key |
SESSION_SECRET_KEY |
— | Required for session middleware |
session_https_only |
SESSION_HTTPS_ONLY |
false |
Marks the fp_session cookie Secure. Required when the app is served over HTTPS and uses OIDC — authlib stores the OIDC state/nonce in this session and the IdP callback is a cross-site redirect, so Safari/iOS drops a non-Secure cookie and login fails with a state mismatch. |
gzip_enabled |
FASTPLUGGY_GZIP_ENABLED |
true |
Enable response gzip compression |
gzip_minimum_size |
FASTPLUGGY_GZIP_MINIMUM_SIZE |
500 |
Minimum response size (bytes) before compressing |
Per-plugin settings
Declare a Pydantic BaseSettings class and assign it to module_settings.
FastPluggy instantiates it at startup and persists values to the database.
from pydantic_settings import BaseSettings
from fastpluggy.core.module_base import FastPluggyBaseModule
class MySettings(BaseSettings):
api_key: str = ""
max_items: int = 100
namespace: str = "my_plugin" # used as DB key prefix — keep unique
class Config:
env_prefix = "MY_PLUGIN_"
class MyPlugin(FastPluggyBaseModule):
module_settings = MySettings # pass the class, not an instance
The settings form is auto-generated and available at /base_module/{module_name}/settings.
Passing an instance fails silently
PluginState checks isinstance(module_settings, type) before using it. Pass an
instance and it never raises and never calls it — it appends
"Settings should be a class, not instance." to the plugin's error, which surfaces
only as a warning triangle on the menu icon.
Omitting module_settings entirely is quieter still: the framework reports the plugin
as having no settings, while the configuration keeps working through env vars and
defaults. It reads as "this plugin has no configuration" rather than as a wiring bug,
so nothing looks broken.
Worth a structural test — and it must read the field on an instance, since
FastPluggyBaseModule is a Pydantic model.
Accessing settings at runtime
# From a lifecycle hook (fast_pluggy injected):
def on_load_complete(self, fast_pluggy):
manager = fast_pluggy.get_manager()
state = manager.modules.get(self.module_name)
cfg = state.settings # MySettings instance with DB-persisted values
# From a route handler:
@router.get("/my-route")
def my_route(fast_pluggy=Depends(get_fastpluggy)):
state = fast_pluggy.get_manager().modules.get("my_plugin")
cfg = state.settings
namespace field
The namespace field (if present) is used as the DB key prefix so multiple plugins
don't overwrite each other's settings. Set it to module_name and make it read-only in
the form: