msgspec-based settings loader with env var, .env, YAML and TOML support
Project description
msgspec-conf
A tiny settings loader inspired by pydantic_settings, but implemented with msgspec. It allows loading structured configuration from environment variables, .env files, YAML and TOML config files without depending on Pydantic.
Features
- Define settings as
msgspec.Structclasses - Load values from the current environment, optional
.envfiles, YAML or TOML config files, and defaults - Automatic type coercion for scalar values and common collection formats
- Optional prefixes and case-insensitive matching
- File-backed secret fallback via
*_FILEvariables - Declarative loading for top-level settings composed from prefixed blocks
Usage
from typing import Optional
import msgspec
from msgspec_conf import BaseSettings
class AppSettings(BaseSettings):
debug: bool = False
database_url: str
api_key: Optional[str] = None
settings = AppSettings.load(env_file=".env", prefix="APP_")
print(settings.database_url)
.env values override defaults, while real environment variables take precedence over the file.
YAML and TOML config files
A config file can supply structured, non-secret configuration — the kind you
commit to git — while .env keeps private values out of the repository. The
two sources are independent: each has its own path and either can be used alone
or together. The file is parsed as TOML when it has a .toml suffix and as YAML
otherwise.
settings = AppSettings.load(config_file="config.yaml", env_file=".env")
# config.yaml — safe to commit
debug: false
host: api.example.com
tags:
- landing
- monitoring
Values resolve with the precedence real env vars > .env file > config file >
defaults. So if HOST appears both in config.yaml and the environment, the
environment wins; fields only present in the config file are still applied.
The same applies to TOML. To read settings straight out of pyproject.toml,
point config_file at it and use config_table to select the table (a dotted
path) that holds your settings:
settings = AppSettings.load(
config_file="pyproject.toml",
config_table="tool.myservice",
)
# pyproject.toml
[tool.myservice]
debug = false
host = "api.example.com"
tags = ["landing", "monitoring"]
config_table works with any config file format; without it the whole document
is used. load_composed_settings accepts both config_file and config_table
as well, so each prefixed block can be configured from a nested table.
Because YAML is already structured, native types are used directly — no string parsing is needed for lists, mappings, or nested records:
limits:
checkout: 20
login: 60
rules:
- { id: 1, score: 95 }
- { id: 2, score: 90 }
Top-level YAML keys are matched against field names case-insensitively.
List values can be written as CSV, semicolon/newline-delimited text, or JSON:
APP_ALLOWED_ORIGINS=https://example.com,https://api.example.com
APP_ALLOWED_LOCALES=en;uk;fr
APP_ALLOWED_TOPICS=["landing.live_stats","monitoring.live_status"]
Dict values can be written as JSON or delimited key-value pairs:
APP_LIMITS={"checkout":20,"login":60}
APP_LIMITS=checkout=20,login:60;refresh=120
list[dict[...]] values can be written as JSON or as records separated by
semicolon/newline. Within each record, comma separates key-value pairs:
APP_RULES=[{"id":"policy.example","score":95,"evidence_urls":["https://example.com"]}]
APP_RULES=id=1,score=95;id=2,score=90
Prefer JSON when values are deeply nested or may contain delimiters.
Boolean values are parsed strictly. Accepted values are 1/0, true/false,
yes/no, on/off, and y/n.
File-backed values
If TOKEN is empty or unset, TOKEN_FILE can point to a file containing the
value:
class SecretSettings(BaseSettings):
token: str = ""
token_file: str | None = None
settings = SecretSettings.load()
TOKEN_FILE=/run/secrets/api_token
The token_file field is optional. TOKEN_FILE also works when only token
is defined.
Composed settings
Services with a top-level msgspec.Struct can load nested settings blocks
declaratively:
from msgspec_conf import BaseSettings, ServiceDefaultsBase, load_composed_settings
import msgspec
class DatabaseSettings(BaseSettings):
host: str = "localhost"
port: int = 5432
class ServiceDefaults(ServiceDefaultsBase):
service_name: str = "example-service"
class Settings(msgspec.Struct, kw_only=True):
debug: bool = False
service_name: str = "example-service"
database: DatabaseSettings = msgspec.field(default_factory=DatabaseSettings)
settings = load_composed_settings(
Settings,
env_file=".env",
defaults_cls=ServiceDefaults,
prefixes={"database": "POSTGRES_"},
)
Default factories on nested fields are preserved and then overridden by matching environment values.
A YAML config file works here too. Top-level keys map to shared fields, while each nested mapping (keyed by the block's field name) configures that block:
settings = load_composed_settings(
Settings,
config_file="config.yaml",
env_file=".env",
defaults_cls=ServiceDefaults,
prefixes={"database": "POSTGRES_"},
)
debug: false
service_name: example-service
database:
host: db.internal
port: 5432
Environment variables (e.g. POSTGRES_HOST) still override the matching YAML
values.
Installation
pip install msgspec-conf
# or
uv add msgspec-conf
Development
uv sync --dev
uv run pytest
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file msgspec_conf-1.3.0.tar.gz.
File metadata
- Download URL: msgspec_conf-1.3.0.tar.gz
- Upload date:
- Size: 9.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f2070043d2bf8e6a4a9d5b4cc45aa1e15ad7e740ce3bbf89030eb77b287afa5e
|
|
| MD5 |
05748c92bb2e6181646e8e48508193f7
|
|
| BLAKE2b-256 |
0e58d3bcc1a549b1a8d75eca7cd44590ca973a964c4b720a35edf2bc64a79fdb
|
File details
Details for the file msgspec_conf-1.3.0-py3-none-any.whl.
File metadata
- Download URL: msgspec_conf-1.3.0-py3-none-any.whl
- Upload date:
- Size: 10.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d630dd76364993b0d34c20b99a8b8553f43717127f2dc82b97f4d6ab8d213fa
|
|
| MD5 |
ccd694b644c49ed29f2a8a6676f09b05
|
|
| BLAKE2b-256 |
5225f523296949f88f73df2ad8880fcd20a341d27119a5c8aaf2d7941ee569fd
|