Core Settings Architecture
The application's configuration is managed by a centralized system built on Pydantic's BaseSettings. This architecture ensures that environment variables are validated, typed, and easily accessible throughout the codebase via a single source of truth.
The core of this system resides in backend/app/core/config.py, where the Settings class defines the application's schema and the settings singleton provides the runtime instance used by other modules.
Environment Variable Management
The Settings class uses Pydantic's SettingsConfigDict to automatically load variables from an environment file. By default, it is configured to look for a .env file located one level above the backend directory:
class Settings(BaseSettings):
model_config = SettingsConfigDict(
# Use top level .env file (one level above ./backend/)
env_file="../.env",
env_ignore_empty=True,
extra="ignore",
)
This setup allows the project to maintain a single environment configuration at the root level that serves both the backend and other services (like the database or frontend) in a containerized environment.
Core Configuration Components
The Settings class organizes configuration into several logical groups, often using computed properties to derive complex values from simple environment variables.
Database Connection
Instead of requiring a full connection string in the environment, the application builds the SQLALCHEMY_DATABASE_URI dynamically. This ensures consistency and allows the application to use the postgresql+psycopg driver specifically.
@computed_field
@property
def SQLALCHEMY_DATABASE_URI(self) -> PostgresDsn:
return PostgresDsn.build(
scheme="postgresql+psycopg",
username=self.POSTGRES_USER,
password=self.POSTGRES_PASSWORD,
host=self.POSTGRES_SERVER,
port=self.POSTGRES_PORT,
path=self.POSTGRES_DB,
)
This URI is then consumed by backend/app/core/db.py to initialize the SQLModel engine:
engine = create_engine(str(settings.SQLALCHEMY_DATABASE_URI))
CORS Configuration
The application handles Cross-Origin Resource Sharing (CORS) by combining a list of origins from the environment with the frontend host. The BACKEND_CORS_ORIGINS variable is processed by a BeforeValidator called parse_cors, which allows it to be provided as either a JSON list or a comma-separated string.
@computed_field
@property
def all_cors_origins(self) -> list[str]:
return [str(origin).rstrip("/") for origin in self.BACKEND_CORS_ORIGINS] + [
self.FRONTEND_HOST
]
Security and Validation
A critical feature of the Settings architecture is its enforcement of security standards. The class includes a _check_default_secret method that prevents the application from running in non-local environments if sensitive keys are left as the default value "changethis".
def _check_default_secret(self, var_name: str, value: str | None) -> None:
if value == "changethis":
message = (
f'The value of {var_name} is "changethis", '
"for security, please change it, at least for deployments."
)
if self.ENVIRONMENT == "local":
warnings.warn(message, stacklevel=1)
else:
raise ValueError(message)
This check is triggered automatically during class instantiation via a model_validator for the SECRET_KEY, POSTGRES_PASSWORD, and FIRST_SUPERUSER_PASSWORD.
Application Integration
The settings singleton is imported across the application to configure various services.
FastAPI Initialization
In backend/app/main.py, the settings instance defines the API metadata, documentation URLs, and middleware:
from app.core.config import settings
app = FastAPI(
title=settings.PROJECT_NAME,
openapi_url=f"{settings.API_V1_STR}/openapi.json",
generate_unique_id_function=custom_generate_unique_id,
)
if settings.all_cors_origins:
app.add_middleware(
CORSMiddleware,
allow_origins=settings.all_cors_origins,
# ... other CORS settings
)
External Services
Settings also control the integration of external tools like Sentry. The application conditionally initializes the Sentry SDK based on the ENVIRONMENT and the presence of a SENTRY_DSN:
if settings.SENTRY_DSN and settings.ENVIRONMENT != "local":
sentry_sdk.init(dsn=str(settings.SENTRY_DSN), enable_tracing=True)
Similarly, email functionality is toggled via the emails_enabled computed property, which checks if the necessary SMTP settings (like SMTP_HOST and EMAILS_FROM_EMAIL) are provided.