FastAPI: From Basics to Production · Pydantic v2 in Depth
Configuration with pydantic-settings
Load typed settings from environment variables and .env files.
pydantic-settings loads configuration from environment variables (and optionally .env files) into a typed BaseSettings class, validating it at startup. Use SecretStr for secrets (masked in repr/logs), prefixes to namespace variables, and provide settings via a cached dependency so tests can override them.
from functools import lru_cache
from typing import Annotated
from fastapi import Depends
from pydantic import PostgresDsn, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_file=".env", env_prefix="APP_")
database_url: PostgresDsn
jwt_secret: SecretStr
access_token_minutes: int = 15
debug: bool = False
@lru_cache
def get_settings() -> Settings:
return Settings()
SettingsDep = Annotated[Settings, Depends(get_settings)]
# APP_DATABASE_URL=postgresql+asyncpg://... APP_JWT_SECRET=...
Common pitfalls
- Reading
os.environall over the codebase. - Logging settings objects containing secrets as plain strings.
- Committing
.envwith real secrets.
Key points
- Typed, validated config at startup
- SecretStr for secrets
- Cached dependency, overridable in tests
Further reading: FastAPI: Settings and environment variables
Practice questions
Why wrap get_settings() with lru_cache?
Answer
So the environment and .env file are read and validated once, not on every request, while still allowing tests to override the dependency.
What does SecretStr protect against?
Answer
Accidental exposure: its repr and str show **********; you must call .get_secret_value() explicitly to use it.
Open in the app to mark lessons complete, take notes and track your progress.