Pydantic Settings typed config from env and .env: working versions (tested 2026-10-15)
Typed app configuration with pydantic-settings: env prefixes, nested settings, secrets and validation errors.
passed3 passed · 0 failed2026-10-15 11:37 UTC- Status
- passed
- Last passed
- 2026-10-15 11:37 UTC
- Tests
- 3 / 3
- Language
- Python
- Runtime
- Python 3.13.16
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt .venv/bin/python -m pytest -q
Python 3.13.16 linux 6.17.0-1022-azure x64 runner: github-actions 38728226240
The code
Exactly the files that passed. Your agent can pull them with get_recipe("pydantic-settings-config") (install), or see them on GitHub.
pydantic==2.14.1 pydantic-settings==2.16.0 pytest==9.1.1
from pydantic import BaseModel, Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class DbSettings(BaseModel):
url: str = "sqlite:///app.db"
pool_size: int = Field(5, ge=1, le=50)
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="APP_", env_nested_delimiter="__", env_file=".env", extra="ignore")
debug: bool = False
api_key: SecretStr
db: DbSettings = DbSettings()
import pytest
from pydantic import ValidationError
from settings import Settings
def test_env_and_nested(monkeypatch):
monkeypatch.setenv("APP_API_KEY", "s3cret")
monkeypatch.setenv("APP_DEBUG", "true")
monkeypatch.setenv("APP_DB__POOL_SIZE", "10")
s = Settings(_env_file=None)
assert s.debug is True and s.db.pool_size == 10
assert s.api_key.get_secret_value() == "s3cret" and "s3cret" not in repr(s)
def test_dotenv(tmp_path, monkeypatch):
monkeypatch.delenv("APP_API_KEY", raising=False)
env = tmp_path / ".env"
env.write_text("APP_API_KEY=fromfile\n")
assert Settings(_env_file=env).api_key.get_secret_value() == "fromfile"
def test_validation(monkeypatch):
monkeypatch.setenv("APP_API_KEY", "x")
monkeypatch.setenv("APP_DB__POOL_SIZE", "500")
with pytest.raises(ValidationError):
Settings(_env_file=None)
[pytest] pythonpath = .
Connect to ProvenPin
Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp
{ "mcpServers": { "provenpin": { "url": "https://mcp.provenpin.com/mcp" } } }{ "servers": { "provenpin": { "type": "http", "url": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "serverUrl": "https://mcp.provenpin.com/mcp" } } }{ "mcpServers": { "provenpin": { "type": "streamableHttp", "url": "https://mcp.provenpin.com/mcp" } } }Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.
Related stacks
pydantic-settings v2 config from env, YAML and defaults with SecretStr
Nested pydantic-settings models loaded with precedence init > env > YAML > defaults, with env_nested_delimiter, SecretStr masking, and offline tests using tmp_path and monkeypatch.
FastAPI + Pydantic v2 validators, discriminated unions and serializers
Pydantic v2 patterns in FastAPI that agents often get wrong: field_validator, model_validator, discriminated unions, computed_field and response_model filtering.
FastAPI background tasks + dependency overrides
FastAPI BackgroundTasks for post-response work, with dependency_overrides to swap services in tests.
FastAPI config via pydantic-settings as a cached dependency
Load config from env vars with pydantic-settings, inject it into FastAPI routes through a cached dependency, and test it offline with monkeypatch and dependency_overrides.