Day 24 · ~12m

Configuration Management

Use pydantic-settings for type-safe configuration from environment variables.

🧑‍💻

My API has hardcoded values everywhere — database URLs, API keys, feature flags. How do I manage these properly?

👩‍🏫

With environment variables and pydantic-settings. The idea: all configuration lives outside your code, loaded from environment variables or .env files. Different environments (dev, staging, prod) use different values without changing a single line of code.

from pydantic_settings import BaseSettings

class Settings(BaseSettings):
    database_url: str = "sqlite:///dev.db"
    api_key: str
    debug: bool = False
    max_connections: int = 10

    model_config = {"env_file": ".env"}

settings = Settings()

BaseSettings reads values from environment variables automatically. DATABASE_URL=postgres://... in your environment becomes settings.database_url. It's case-insensitive and type-validated.

🧑‍💻

What if a required variable is missing?

👩‍🏫

Pydantic raises a validation error at startup — before your app handles any requests. Fields without defaults are required:

class Settings(BaseSettings):
    api_key: str          # Required — crash if missing
    debug: bool = False   # Optional — defaults to False

This is called fail-fast. Better to crash on startup with a clear error than to crash on the first request when you try to use a missing key.

🧑‍💻

How do I use this with FastAPI?

👩‍🏫

Create the settings once and inject them via dependency:

from functools import lru_cache

@lru_cache()
def get_settings():
    return Settings()

@app.get("/config")
def show_config(settings: Settings = Depends(get_settings)):
    return {
        "debug": settings.debug,
        "max_connections": settings.max_connections
    }

@lru_cache() ensures Settings is created only once and reused. The .env file is read once at startup, not on every request.

🧑‍💻

What about secrets? I don't want API keys in my .env file in production.

👩‍🏫

In production, set environment variables directly — through your deployment platform (Railway, Vercel, AWS). The .env file is for local development only:

# .env — local development only, NEVER commit this DATABASE_URL=sqlite:///dev.db API_KEY=dev-key-123 DEBUG=true

Add .env to your .gitignore. Production secrets come from the platform's environment variable settings, not files. Your code doesn't care where the values come from — BaseSettings reads them the same way.

Practice your skills

Sign up to write and run code in this lesson.

Already have an account? Sign in