Skip to content

Configuration

The application is configured using environment variables and Pydantic Settings. This ensures strict type validation for all configuration options.

Environment-Based Configuration

The application supports three environments with automatic .env file selection based on the ENV variable:

Environment ENV Value Config File Use Case
Development development (default) .env Local development
Test test .env.test Test suite, CI/CD
Production production .env.production Production deployment

The environment is determined at startup from the QUOIN_ENV environment variable, with ENV as a fallback for backward compatibility.

Environment Variable Prefix

All application settings use the QUOIN_ prefix for namespacing. This prevents conflicts with system or other application variables.

# Example: setting log level
export QUOIN_LOG_LEVEL=DEBUG

# Without prefix (won't work)
export LOG_LEVEL=DEBUG  # ❌ Ignored

Setup

Copy the example configuration to create your local .env file:

cp .env.example .env

The template contains these defaults — ready for local development with Docker:

# Application
# Environment: development, test, production
QUOIN_ENV=development
QUOIN_LOG_LEVEL=INFO
QUOIN_OTEL_ENABLED=True

# Database
QUOIN_POSTGRES_DRIVER=postgresql+asyncpg
QUOIN_POSTGRES_HOST=localhost
QUOIN_POSTGRES_PORT=5432
QUOIN_POSTGRES_USER=postgres
QUOIN_POSTGRES_PASSWORD=postgres
QUOIN_POSTGRES_DB=app_db

Note

The defaults work out of the box with just db. For production, override QUOIN_POSTGRES_HOST, QUOIN_POSTGRES_PASSWORD, and set QUOIN_ENV=production.

Creating Environment-Specific Files

Create .env.test for test-specific settings:

# .env.test
QUOIN_ENV=test
QUOIN_LOG_LEVEL=DEBUG
QUOIN_OTEL_ENABLED=False
QUOIN_POSTGRES_DB=test_db

Create .env.production for production settings (never commit this):

# .env.production
QUOIN_ENV=production
QUOIN_LOG_LEVEL=WARNING
QUOIN_OTEL_ENABLED=True
QUOIN_POSTGRES_HOST=your-prod-db-host
# ... other production settings

Key Settings

Variable Description Default
QUOIN_ENV Environment (development, test, production) development
QUOIN_LOG_LEVEL Logging level (DEBUG, INFO, WARNING, ERROR) INFO
QUOIN_OTEL_ENABLED Enable OpenTelemetry tracing true
QUOIN_POSTGRES_DRIVER Database driver postgresql+asyncpg
QUOIN_POSTGRES_HOST PostgreSQL host localhost
QUOIN_POSTGRES_PORT PostgreSQL port 5432
QUOIN_POSTGRES_USER PostgreSQL username postgres
QUOIN_POSTGRES_PASSWORD PostgreSQL password postgres
QUOIN_POSTGRES_DB PostgreSQL database name app_db
QUOIN_REQUEST_TIMEOUT_SECONDS Per-request wall-clock timeout (0 = disabled) 30.0
QUOIN_SHUTDOWN_DRAIN_TIMEOUT Max seconds to drain in-flight requests on shutdown (<=0 = no wait) 30.0
QUOIN_REQUEST_ID_HEADER Header name for request ID propagation X-Request-ID
QUOIN_ALLOWED_HOSTS Trusted host list ["localhost", "127.0.0.1", "test", "*.orb.local"]
QUOIN_BACKEND_CORS_ORIGINS CORS allowed origins (empty = CORS disabled) ["http://localhost:3000", "http://localhost:8000"]
QUOIN_BACKEND_CORS_ALLOW_METHODS Allowed HTTP methods for CORS ["GET","POST","PUT","PATCH","DELETE","OPTIONS"]
QUOIN_BACKEND_CORS_ALLOW_HEADERS Allowed request headers for CORS ["Authorization","Content-Type","X-Request-ID"]
QUOIN_BACKEND_CORS_ALLOW_CREDENTIALS Allow cookies/credentials in CORS requests true
QUOIN_SECURITY_HEADERS_ENABLED Enable security response headers middleware true
QUOIN_SECURITY_HSTS_MAX_AGE HSTS max-age in seconds (0 = disabled) 31536000
QUOIN_SECURITY_HSTS_INCLUDE_SUBDOMAINS Add includeSubDomains to HSTS true
QUOIN_SECURITY_HSTS_PRELOAD Add preload to HSTS header false
QUOIN_SECURITY_CSP Content-Security-Policy header value See Security guide
QUOIN_SECURITY_REFERRER_POLICY Referrer-Policy header value strict-origin-when-cross-origin
QUOIN_SECURITY_PERMISSIONS_POLICY Permissions-Policy header value geolocation=(), camera=(), microphone=()
QUOIN_MAX_REQUEST_BODY_BYTES Max request body size in bytes (<=0 = disabled) 1048576 (1 MiB)
QUOIN_HTTP_TIMEOUT_SECONDS Outbound request timeout in seconds (all phases) 10.0
QUOIN_HTTP_RETRY_ATTEMPTS Total attempts per outbound call (1 = no retry) 3

Finer backoff and circuit-breaker tuning are module constants in app/http/client.py rather than settings; the connection pool uses httpx defaults. See the Outbound HTTP Client guide.

Core Settings Module

All settings are defined in app/core/config.py. The Settings class defines the schema and validation rules.

from enum import StrEnum
from pydantic import PostgresDsn, computed_field
from pydantic_settings import BaseSettings

class Environment(StrEnum):
    """Application environment."""
    development = "development"
    test = "test"
    production = "production"

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_prefix="quoin_",
        case_sensitive=False,
        env_file=env_file,  # Automatically selected
    )

    ENV: Environment = Environment.development
    LOG_LEVEL: str = "INFO"
    OTEL_ENABLED: bool = True

    # Database - constructed from individual POSTGRES_* vars
    POSTGRES_HOST: str = "localhost"
    POSTGRES_PORT: int = 5432
    # ... other POSTGRES_* fields

    @computed_field
    @property
    def DATABASE_URL(self) -> PostgresDsn:
        \"\"\"Assemble the database URL.\"\"\"
        # Constructed from POSTGRES_* fields

Database Configuration

The database connection is managed in app/db/session.py. The async engine is created via create_db_engine() and stored on app.state.engine during the application lifespan. It uses SQLModel (a wrapper around SQLAlchemy) with the async asyncpg driver for high performance.

  • Changes: Never modify the database schema manually. Always change the SQLModel definition in Python.
  • Migrations: Use just migrate-gen \"message\" to generate migration scripts.

See Also