Supported Types¶
dotenvmodel supports a wide range of Python types with automatic coercion from environment variable strings. This page covers every supported type with code examples and the expected environment variable format.
For the complete API reference, see Types API.
Basic Types¶
Booleans accept multiple string formats (case-insensitive):
- True:
"true","1","yes","on","t","y" - False:
"false","0","no","off","f","n",""
Path fields are resolved by default (expanduser + resolve). Use resolve_path=False to keep raw paths.
Collection Types¶
Collection types are parsed from comma-separated strings by default. Use the separator parameter to change the delimiter.
Sets automatically deduplicate values.
Dicts use key=value pairs separated by the separator (default comma).
Custom separators
If your values contain commas, use a different delimiter: separator=";", separator="|", etc. The separator applies to list, set, tuple, and dict types.
Advanced Types¶
Use uuid_version to require a specific UUID version. See Validation.
Use Decimal for precise arithmetic (e.g., monetary values).
datetime fields use ISO 8601 format.
timedelta accepts human-readable duration strings.
Supported units (case-insensitive): ms, s, m, h, d, w
# .env — all of these produce timedelta(hours=1, minutes=30):
CACHE_TTL=1h30m
# or as plain seconds:
CACHE_TTL=5400
Duration formats
| Format | Meaning |
|---|---|
90 |
90 seconds |
90s |
90 seconds |
1h30m |
1 hour 30 minutes |
2d |
2 days |
500ms |
500 milliseconds |
1w |
1 week |
1d2h30m |
1 day 2 hours 30 minutes |
Secret Types¶
SecretStr¶
SecretStr hides sensitive values in logs and repr output. Use it for API keys, passwords, and tokens.
from dotenvmodel import DotEnvConfig, Field
from dotenvmodel.types import SecretStr
class Config(DotEnvConfig):
api_key: SecretStr = Field(min_length=32)
password: SecretStr = Field()
config = Config.load()
print(config.api_key) # SecretStr('**********')
print(repr(config.api_key)) # "SecretStr('**********')"
print(config.api_key.get_secret_value()) # 'super-secret-key-with-at-least-32-chars'
SecretStr cannot be pickled
SecretStr prevents pickling for security reasons. Extract the value with get_secret_value() before serializing if needed.
URL and DSN Types¶
URL/DSN types work like strings but validate the scheme and provide parsed components as properties. Import them from dotenvmodel.types.
Validates http and https URLs.
Validates PostgreSQL connection strings. Accepts postgresql:// and postgres:// schemes. Default port: 5432.
Validates Redis connection strings. Accepts redis:// and rediss:// (SSL) schemes. Default port: 6379.
Available properties
All DSN types inherit from BaseDsn and provide: scheme, host, port, path, query, username, password. PostgresDsn and RedisDsn add a database property.
JSON Parsing¶
Use Json[T] to parse JSON strings into Python objects. The inner type parameter controls validation:
Json[dict]— validates the parsed result is a dictJson[list]— validates the parsed result is a list- Other inner types are accepted but not deeply validated
from dotenvmodel import DotEnvConfig, Field
from dotenvmodel.types import Json
class Config(DotEnvConfig):
# JSON object
feature_flags: Json[dict[str, bool]] = Field()
# JSON array
allowed_roles: Json[list[str]] = Field()
# JSON without type validation
raw_config: Json = Field()
# .env
FEATURE_FLAGS={"new_ui": true, "beta_api": false}
ALLOWED_ROLES=["admin", "user", "guest"]
RAW_CONFIG={"nested": {"value": 42}}
config = Config.load()
assert config.feature_flags == {"new_ui": True, "beta_api": False}
assert config.allowed_roles == ["admin", "user", "guest"]
Json vs comma-separated lists
Use Json[list[str]] when values may contain commas or need complex structure. Use list[str] with separator for simple comma-separated values — it's lighter weight.
Optional Types¶
Optional types automatically default to None if no explicit default is provided. Both modern union syntax (str | None) and Optional[str] from typing work.
from typing import Optional
class Config(DotEnvConfig):
# These automatically default to None — no need for default=None
optional_value: str | None = Field()
optional_port: int | None = Field()
# Using Optional from typing also works
optional_name: Optional[str] = Field()
# You can still provide explicit defaults
optional_with_default: str | None = Field(default="custom")
config = Config.load() # No env vars set
assert config.optional_value is None
assert config.optional_port is None
assert config.optional_name is None
assert config.optional_with_default == "custom"
Non-optional unions not supported
Types like str | int or Union[str, int] (without None) are not supported. Only optional unions work. Use a single type (typically str) and handle conversion in your application code.
Enum Types¶
Enum fields are coerced by matching the environment variable string against enum member values (case-sensitive) or names (case-insensitive).
from enum import Enum
class LogLevel(Enum):
DEBUG = "debug"
INFO = "info"
WARNING = "warning"
ERROR = "error"
class Config(DotEnvConfig):
log_level: LogLevel = Field(default=LogLevel.INFO)
# .env — match by value (case-sensitive)
LOG_LEVEL=debug
# or match by name (case-insensitive)
LOG_LEVEL=DEBUG
Enum in describe output
When you use describe() or generate_env_example(), enum types display their allowed values automatically (e.g., LogLevel (debug, info, warning, error)).
Optional enums also work:
See Also¶
- Field Definitions — how to define fields with
Field() - Validation — constraints for all types
- Types API — auto-generated API reference