Skip to content

Getting Started

Install and run your first configuration loader in 5 minutes.

Installation

uv add utilityhub_config

Optional dependencies:

# For YAML support
uv add pyyaml

# For .env file support
uv add python-dotenv

Your First Config

Create a simple configuration:

from pydantic import BaseModel
from utilityhub_config import load_settings

class Config(BaseModel):
    database_url: str = "sqlite:///default.db"
    debug: bool = False
    workers: int = 4

# Load settings from all available sources
settings, metadata = load_settings(Config)

# Use your settings
print(f"Database: {settings.database_url}")
print(f"Debug mode: {settings.debug}")
print(f"Workers: {settings.workers}")

That's it! load_settings() automatically:

  1. Uses model field defaults
  2. Checks ~/.config/config/config.toml and ~/.config/config/config.yaml
  3. Checks ./config.toml, ./config.yaml, and files in ./config/
  4. Reads .env in current directory
  5. Checks environment variables (DATABASE_URL, DEBUG, WORKERS)

See Where Values Come From

settings, metadata = load_settings(Config)

# Check the source of a field
source = metadata.get_source("database_url")
print(f"Came from: {source.source}")        # "env", "project", "defaults", etc.
print(f"File: {source.source_path}")        # Full path or "ENV:DATABASE_URL"
print(f"Raw value: {source.raw_value}")     # Original value before validation

Next Steps

Choose your path:

👉 Want to understand precedence? Read Precedence Order

👉 Ready to use files? Jump to Configuration Files guide

👉 Using environment? See Environment Variables guide

👉 Need specific patterns? Browse Usage Guides

👉 Troubleshooting? Check Troubleshooting guide

Common Tasks

Use a Config File

from pathlib import Path

settings, _ = load_settings(
    Config,
    config_file=Path("./production.yaml")
)

See Explicit Config Files guide

Use Environment Variable Prefix

settings, _ = load_settings(
    Config,
    env_prefix="MYAPP"  # Looks for MYAPP_DATABASE_URL, etc.
)

See Environment Variables guide

Disable Environment Variables

settings, _ = load_settings(
    Config,
    env_vars=False
)

No environment variable lookup is performed when env_vars=False, even if env_prefix is provided.

Dynamic Extension Schemas

from pydantic import BaseModel

class ComponentConfig(BaseModel):
    threshold: float = 0.75
    model_path: str = "~/default/path"

class AppConfig(BaseModel):
    app_name: str = "myapp"
    plugins: dict[str, object] = {}

settings, metadata = load_settings(
    AppConfig,
    extension_root="plugins",
    extension_schemas={"component_a": ComponentConfig},
)

# Recommended access pattern for validated extension sections:
component_a = metadata.extension_configs["component_a"]
print(component_a.threshold)
print(component_a.model_path)

This validates plugins.component_a against ComponentConfig and preserves the typed extension configuration. Use metadata.extension_configs to access the resulting validated extension models.

Override at Runtime

settings, _ = load_settings(
    Config,
    overrides={
        "debug": True,
        "workers": 8
    }
)

See Runtime Overrides guide

Handle Errors

from utilityhub_config.errors import ConfigValidationError

try:
    settings, _ = load_settings(Config)
except ConfigValidationError as e:
    print(f"Configuration error: {e}")

See Error Handling guide

What's Different?

utilityhub_config is explicit, not magical:

  • ✅ Precedence is clear and documented
  • ✅ You know exactly where each setting came from (metadata)
  • ✅ Type safety via Pydantic
  • ✅ No hidden behavior - what you see is what you get
  • ✅ Rich errors when validation fails

Learn More