---
title: Configuration Models
description: Type-safe Pydantic configuration models for Django-CFG
sidebar_label: Configuration Models
sidebar_position: 1
---

# Configuration Models

Django-CFG uses Pydantic v2 models for type-safe, validated configuration.


<Callout type="info">
**Why Type-Safe Configuration?**
Type-safe configuration catches errors at **startup** instead of runtime, provides **IDE autocomplete**, and enables **static type checking** with mypy/pyright.

</Callout>

## Quick Start

### Python Config

```python filename="config.py"
from django_cfg import DjangoConfig
from pydantic import BaseModel

class DatabaseConfig(BaseModel):
    url: str = "sqlite:///db/default.sqlite3"

class MyProjectConfig(DjangoConfig):
    # Core settings
    secret_key: str = "your-secret-key-here"
    debug: bool = True
    project_name: str = "My Project"

    # Database
    database: DatabaseConfig = DatabaseConfig()

    # Services (optional)
    # email: EmailConfig = EmailConfig()
    # telegram: TelegramConfig = TelegramConfig()
```

### YAML Config

```yaml filename="config.yaml"
secret_key: "dev-secret-key"
debug: true
project_name: "My Project"

database:
  url: "sqlite:///db/default.sqlite3"

# Optional services
# email:
#   backend: "console"
# telegram:
#   bot_token: "your-token"
```

```python filename="config.py"
from django_cfg import DjangoConfig, load_config

# Load from YAML
config = load_config()  # Reads config.yaml
```


## Configuration Topics

### Core Configuration

- [**DjangoConfig**](./django-settings) - Base configuration class
- [**Security Settings**](./security) - Security, CORS, SSL configuration
- [**Environment**](./environment) - Environment detection and variables

### Infrastructure

- [**Database**](./database) - Database configuration
- [**Cache**](./cache) - ✨ **Auto Redis cache** from `redis_url` (Redis, LocMem, Dummy)
- [**Logging**](../deployment/logging) - Logging configuration

### Deployment

- [**Docker Configuration**](../guides/docker/configuration) - YAML + environment variables for Docker

### Services

- [**Email**](./email) - Email services (SMTP, Console)
- [**Telegram**](../features/modules/django-telegram/overview) - Telegram bot configuration

### Security

- [**Two-Factor Authentication**](/docs/features/integrations/auth#two-factor-authentication-2fa) - TOTP-based 2FA configuration

### Django Integrations

- [**Admin & UI**](../features/modules/django-unfold/overview) - Unfold admin interface
- [**API**](../features/integrations/overview) - DRF, Spectacular, JWT

## Key Features

### Type Safety


<Callout type="info">
**Automatic Type Validation**
Pydantic validates all types automatically at instantiation time, preventing runtime errors.

</Callout>

```python
# Pydantic validates types automatically
class MyConfig(DjangoConfig):
    debug: bool = True
    max_connections: int = 100
    timeout: float = 30.0

# ✅ This works
config = MyConfig(debug=True, max_connections=50)

# ❌ This fails with validation error
config = MyConfig(debug="yes", max_connections="fifty")
```

<details>
  <summary>See validation error output</summary>

```python
ValidationError: 2 validation errors for MyConfig
debug
  Input should be a valid boolean [type=bool_type]
max_connections
  Input should be a valid integer [type=int_type]
```

</details>

### Environment Variables

### Automatic Loading

```python
from pydantic_settings import BaseSettings

class DatabaseConfig(BaseSettings):
    url: str = "sqlite:///db/default.sqlite3"

    class Config:
        env_prefix = "DATABASE_"

# Automatically reads DATABASE_URL from environment
config = DatabaseConfig()
```

### Manual Loading

```python
import os

class DatabaseConfig(BaseModel):
    url: str = os.getenv("DATABASE_URL", "sqlite:///db/default.sqlite3")
```



<Callout type="warning">
**Environment Variables in Production**
Always use environment variables for **secrets** (API keys, passwords) in production. Never commit them to version control.

</Callout>

### YAML Configuration

### Basic YAML

```yaml filename="config.yaml"
secret_key: "dev-secret-key"
debug: true
project_name: "My Project"

database:
  url: "postgresql://localhost/mydb"

email:
  backend: "console"
```

### With Environment Variables

```yaml filename="config.yaml"
# Use ${VAR_NAME} for environment variable substitution
secret_key: "${SECRET_KEY}"
debug: false
project_name: "My Project"

database:
  url: "${DATABASE_URL}"

email:
  host: "${EMAIL_HOST}"
  password: "${EMAIL_PASSWORD}"
```


```python filename="config.py"
# Load from YAML
from django_cfg import load_config

config = load_config()  # Reads config.yaml
```


<Callout type="info">
**YAML Best Practice**
Keep sensitive values in environment variables and reference them in YAML with `${VAR_NAME}` syntax.

</Callout>

### Validation

```python
from pydantic import Field, field_validator

class MyConfig(DjangoConfig):
    secret_key: str = Field(..., min_length=50)
    max_connections: int = Field(default=100, ge=1, le=1000)

    @field_validator('secret_key')
    def validate_secret_key(cls, v):
        if v == "changeme":
            raise ValueError("Please change the default secret key")
        return v
```


<Callout type="info">
**Pydantic Validators**

Use `field_validator` for custom validation logic. Validators run automatically during configuration instantiation.

</Callout>

## Configuration Patterns

### Development vs Production

### Using Properties

```python filename="config.py"
from django_cfg import DjangoConfig, Environment

class MyConfig(DjangoConfig):
    @property
    def debug(self) -> bool:
        return Environment.current() == Environment.DEVELOPMENT

    @property
    def database_url(self) -> str:
        if Environment.is_production():
            return "postgresql://prod-db/main"
        return "sqlite:///db/dev.sqlite3"
```

### Separate Configs

```python filename="config.py"
class BaseConfig(DjangoConfig):
    project_name: str = "My Project"

class DevConfig(BaseConfig):
    debug: bool = True
    database_url: str = "sqlite:///dev.db"

class ProdConfig(BaseConfig):
    debug: bool = False
    database_url: str = "postgresql://prod-db/main"

# Select based on environment
import os
config = ProdConfig() if os.getenv("ENV") == "production" else DevConfig()
```


### Nested Configuration

```python
class DatabaseConfig(BaseModel):
    url: str
    pool_size: int = 5

class CacheConfig(BaseModel):
    backend: str = "redis"
    location: str = "redis://localhost:6379/1"

class MyConfig(DjangoConfig):
    database: DatabaseConfig
    cache: CacheConfig
```


<Callout type="info">
**Organize Complex Configs**
Use nested Pydantic models to organize complex configurations into logical groups.

</Callout>

### Optional Features

```python
class MyConfig(DjangoConfig):
    # Optional email configuration
    email: Optional[EmailConfig] = None

    # Enable optional features
    enable_telegram: bool = False
```

<details>
  <summary>Example: Conditional Feature Enabling</summary>

```python
class MyConfig(DjangoConfig):
    # Enable features based on environment
    enable_telegram: bool = Field(
        default_factory=lambda: os.getenv("ENABLE_TELEGRAM", "false") == "true"
    )
```

</details>

## See Also

### Configuration Deep Dive
- [**Type-Safe Configuration**](../core/type-safety) - Why type safety matters
- [**Environment**](./environment) - Environment detection and YAML config
- [**Database**](../database) - Database configuration details

### Docker Deployment
- [**Docker Configuration**](../guides/docker/configuration) - Layered config strategy for Docker
- [**Docker Overview**](../guides/docker/overview) - Complete Docker deployment guide
