Install & Compatibility
Where this runs
tested against v25.3.0 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslpy 3.10–3.910 runs
installs and imports cleanly · install 0.0s · import 0.163s · 32.1MB
glibcpy 3.10–3.910 runs
installs and imports cleanly · install 2.8s · import 0.146s · 32MB
30MB installed
● package 30MB
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
load_settings
✓ from typed_settings import load_settings
✗ from typed_settings import settings
load
✓ from typed_settings import load
✗ from typed_settings import settings
EnvLoader
✓ from typed_settings import EnvLoader
✗ from typed_settings import settings
Define settings using `attrs` or `dataclasses` (or Pydantic with optional dependency) with type hints and default values. Use `ts.load` to automatically load and merge settings from config files and environment variables, with later sources overriding earlier ones. Environment variables follow an `APPNAME_OPTION_NAME` pattern by default. `SecretStr` can be used to prevent secrets from being printed in plaintext.
import attrs
from pathlib import Path
import typed_settings as ts
import os
@attrs.frozen
class DatabaseSettings:
host: str = "localhost"
port: int = 5432
user: str = "admin"
password: ts.SecretStr = ts.SecretStr("")
@ts.settings
class AppSettings:
debug: bool = False
log_level: str = "INFO"
database: DatabaseSettings = attrs.field(factory=DatabaseSettings)
# Simulate a config file
config_content = '''
[myapp]
debug = true
log-level = "DEBUG"
[myapp.database]
host = "my.db.server"
port = 6000
'''
config_file_path = Path("settings.toml")
config_file_path.write_text(config_content)
# Simulate environment variables
os.environ['MYAPP_DATABASE_USER'] = os.environ.get('MYAPP_DATABASE_USER', 'env_user')
os.environ['MYAPP_DATABASE_PASSWORD'] = os.environ.get('MYAPP_DATABASE_PASSWORD', 'env_secret')
try:
settings = ts.load(
cls=AppSettings,
appname="myapp",
config_files=[config_file_path],
config_file_section="myapp",
)
print(f"Debug: {settings.debug}")
print(f"Log Level: {settings.log_level}")
print(f"DB Host: {settings.database.host}")
print(f"DB Port: {settings.database.port}")
print(f"DB User: {settings.database.user}")
print(f"DB Password (hidden): {settings.database.password}")
except Exception as e:
print(f"Error loading settings: {e}")
finally:
config_file_path.unlink(missing_ok=True)
del os.environ['MYAPP_DATABASE_USER']
del os.environ['MYAPP_DATABASE_PASSWORD']
typed-settings --version
Debug
Known issues
breakingSince version 25.0.0, dictionary values are no longer merged across different settings sources; instead, they are fully overridden. This changes the behavior from previous versions where dictionaries might have been deeply merged.fixReview configuration files and environment variables to ensure dictionary settings are explicitly complete in the highest-precedence source, as partial definitions will be replaced entirely.
affects: >=25.0.0
breakingAs of a past breaking change, a `ValueError` is now raised if a config file contains options not defined in the settings class. Previously, these might have been silently ignored.fixEnsure all options in your config files correspond to attributes in your settings class, or remove extraneous options from the config.
affects: V2.0.0 onwards (specifically noted in 23.0.0 changelog as a breaking change).
breakingFor CLI integration, Click options without a default value (or a loaded value from other sources) are now automatically marked as `required=True`.fixExplicitly provide default values for optional CLI options in your settings class, or be aware that their absence will require them on the command line.
affects: V2.0.0 onwards (specifically noted in 23.0.0 changelog as a breaking change).
gotchaTyped Settings, since version 23.1.0, automatically resolves paths loaded from config files relative to the config file's directory, and paths from environment variables/CLI args relative to the current working directory. This might differ from previous behavior where paths were treated as absolute or un-resolved.fixAdjust paths in your configuration files or environment variables if they were previously implicitly resolved differently. To disable this, manually create a converter with `resolve_paths=False` and pass it to `load_settings()` if fine-grained control is needed.
affects: >=23.1.0
gotchaPassing secrets directly via environment variables is strongly discouraged due to security risks (e.g., accidental leaks in logs or CI/CD).fixInstead of `MYAPP_API_TOKEN="secret"`, store secrets in a file and pass the file path via an environment variable (e.g., `MYAPP_API_TOKEN_FILE=/private/token`), or use a dedicated secret vault loader. The library provides `SecretStr` to mask values in string representations.
affects: All versions
deprecatedSupport for Python 3.7 was dropped with the 23.1.0 release. Users on Python 3.7 will need to upgrade their Python version.fixUpgrade to Python 3.8 or newer.
affects: <23.1.0 (dropped in 23.1.0)
breakingThe converter API and internal settings dict underwent breaking changes in version 23.1.0. This primarily affects users who have written custom loaders or extended the default converter.fixReview and update custom converter implementations and loaders according to the `typed-settings` documentation for version 23.1.0 and later.
affects: >=23.1.0
Upgrade
Version history
25.3.0latest on PyPI · released Nov 29, 2025
Audit
Dependencies
attrsoptionalRecommended for defining settings classes, via `typed-settings[attrs]`.
pydanticoptionalAlternative for defining settings classes, via `typed-settings[pydantic]`.
cattrsoptionalPowerful and fast converter; used by default if available, via `typed-settings[cattrs]`.
clickoptionalFor generating Click-based command-line interfaces, via `typed-settings[click]`.
python-dotenvoptionalFor reading .env files, via `typed-settings[dotenv]`.
jinja2optionalFor value interpolation with Jinja templates, via `typed-settings[jinja]`.
orjsonoptionalFaster JSON loading, via `typed-settings[orjson]`.
PyYAMLoptionalFor loading YAML files, via `typed-settings[yaml]`.
tomlirequiredRequired for TOML support on Python <= 3.10; used by default on 3.11+ via `tomllib`.