omegaconf review
OmegaConf 2.3.1 is a Python configuration tree for projects that combine YAML files, dataclass schemas, dictionaries, and command-line overrides. Its DictConfig and ListConfig containers support ordered merging, lazy references between values, environment lookups, mandatory placeholders, read-only trees, and rejection of unknown keys. Structured configs check assigned values against dataclass or attrs annotations at runtime. The current 2.3.1 release is a packaging fix for source installs on setuptools versions that removed pkg_resources; the configuration API remains on the 2.3 line. Our sandbox install was pure Python, included py.typed, and imported successfully.
OmegaConf 2.3.1 installed in 1.7 seconds, occupied 4 MB across three packages, and produced zero audit findings in our sandbox, making its runtime cost modest for layered Python configuration. Install it when merging, interpolation, and dataclass-backed checks will all be used; a single YAML file does not justify its second object model.
We installed it
| Install | ✓ · 1.7s | 3 packages on disk · 4 MB |
| Import | ✓ | import omegaconf in 0.29s · pure Python · py.typed · requires Python >=3.6 |
| Known vulns | 0 | (pip-audit) |
Answers from our run
Does omegaconf install cleanly?
Yes. In a fresh container with an empty cache, pip install omegaconf finished in 2 seconds, leaving 3 packages and 4 MB on disk. pip-audit reported no known vulnerabilities.
What does omegaconf need to run?
Python >=3.6, and nothing compiled: it is pure Python. In our run import omegaconf succeeded in 0.29s, and the package ships py.typed for type checkers.
omegaconf or pydantic-settings: which should you use?
pydantic-settings: Choose it when Pydantic models and environment variables already define application settings. OmegaConf 2.3.1 installed in 1.7 seconds, occupied 4 MB across three packages, and produced zero audit findings in our sandbox, making its runtime cost modest for layered Python configuration.
When should you not use omegaconf?
Your program reads one fixed YAML file; PyYAML avoids OmegaConf's container types, flags, and interpolation syntax
Use it if
- Your application composes defaults, environment files, and command-line dotlist overrides in a defined order
- A dataclass should set the allowed configuration shape while YAML remains the format operators edit
- Values need lazy references to sibling keys or environment variables before startup resolves the final tree
- A Hydra application already hands your code DictConfig and ListConfig objects
- Your program reads one fixed YAML file; PyYAML avoids OmegaConf's container types, flags, and interpolation syntax
- Pydantic Settings already owns validation and environment parsing, because a second settings model creates duplicate rules
- Another dependency requires an incompatible antlr4-python3-runtime release; OmegaConf 2.3.1 pins the 4.9 series
- Downstream functions require ordinary dataclass instances, dictionaries, or lists and you do not want an explicit conversion boundary
- You need APIs from the 2.4 development documentation while your deployment policy allows stable PyPI releases only
Setup reality
We installed OmegaConf 2.3.1 in a clean Python 3.12 container in 1.7 seconds. The result was three packages using 4 MB on disk, and pip-audit reported zero known vulnerabilities. Package metadata counted three direct dependencies and allowed Python 3.6 or newer. It is pure Python, carries py.typed, and import omegaconf completed in 0.29 seconds. Check the exact antlr4-python3-runtime pin before adding it to an environment that already has parser tooling.
There is no account, credential, daemon, or required project file. Start with OmegaConf.load() for YAML or OmegaConf.structured() for a dataclass, then merge sources from lowest to highest priority. In a 3-layer setup, the rightmost input wins when the same mapping key appears again. Lists do not behave like recursively merged dictionaries, so test replacement semantics with your actual files.
Interpolations resolve when a value is read. A missing ${oc.env:NAME}, a resolver exception, a reference cycle, or a ??? placeholder can therefore remain hidden during construction. Check OmegaConf.missing_keys() after the final merge and resolve or convert the tree at startup when configuration errors should stop the process. The oc.env resolver returns text; wrap it with oc.decode when YAML-style conversion to a number or boolean is intended.
Type checking a structured config does not turn DictConfig into the original dataclass. Use OmegaConf.to_object() when an API expects dataclass instances, or to_container(resolve=True) when it expects built-in collections. Resolver registration is process-wide, and a duplicate name raises unless replace=True is deliberate. Hydra pins a compatible OmegaConf range, so upgrade the pair together instead of forcing 2.3.1 into an unmatched Hydra environment.
Patterns
Build a nested configuration tree create-config
from omegaconf import OmegaConf
cfg = OmegaConf.create({
"server": {"host": "127.0.0.1", "port": 8000},
"features": ["search", "billing"],
})
print(cfg.server.port)
print(cfg["features"][0])Nested mappings and lists become DictConfig and ListConfig objects. Both attribute access and item access operate on the configuration nodes.
Apply file and CLI overrides in priority order merge-overrides
from omegaconf import OmegaConf
base = OmegaConf.load("config/base.yaml")
environment = OmegaConf.load("config/production.yaml")
cli = OmegaConf.from_cli()
cfg = OmegaConf.merge(base, environment, cli)Later inputs win for repeated mapping keys. `from_cli()` reads the process argument list, so coordinate it with argparse or another CLI parser.
Check file values against a dataclass validate-dataclass
from dataclasses import dataclass
from omegaconf import OmegaConf
@dataclass
class ServerConfig:
host: str = "127.0.0.1"
port: int = 8000
schema = OmegaConf.structured(ServerConfig)
file_values = OmegaConf.load("server.yaml")
cfg = OmegaConf.merge(schema, file_values)Place the schema first and user values later. Invalid assignments raise during the merge, while the merged result remains a DictConfig.
Compose nested typed sections nest-structured-configs
from dataclasses import dataclass, field
from omegaconf import OmegaConf
@dataclass
class Database:
url: str = "sqlite:///app.db"
@dataclass
class AppConfig:
debug: bool = False
database: Database = field(default_factory=Database)
cfg = OmegaConf.structured(AppConfig)Use `default_factory` for nested mutable defaults. OmegaConf reads the field annotations to validate later assignments inside each section.
Derive one path from another setting reference-values
from omegaconf import OmegaConf
cfg = OmegaConf.create({
"root": "/srv/example",
"uploads": "${root}/uploads",
})
print(cfg.uploads)Interpolation is lazy. Changing `root` changes the value returned for `uploads` until the configuration is explicitly resolved or converted.
Read environment values with defaults and conversion read-environment
from omegaconf import OmegaConf
cfg = OmegaConf.create({
"host": "${oc.env:APP_HOST,127.0.0.1}",
"port": "${oc.decode:${oc.env:APP_PORT,8000}}",
"token": "${oc.env:APP_TOKEN}",
})`oc.env` returns strings and raises when a variable has no value or default. `oc.decode` parses YAML-style scalar text such as `8000` or `true`.
Find mandatory values before startup continues reject-missing-values
from omegaconf import MISSING, OmegaConf
cfg = OmegaConf.create({"database": {"password": MISSING}})
missing = OmegaConf.missing_keys(cfg)
if missing:
names = ", ".join(sorted(missing))
raise RuntimeError(f"Missing configuration: {names}")A mandatory value is written as `???` in YAML. Reading one raises MissingMandatoryValue, while `missing_keys()` lets startup report the full set first.
Register a calculated interpolation register-resolver
from omegaconf import OmegaConf
OmegaConf.register_new_resolver(
"times",
lambda left, right: left * right,
use_cache=True,
)
cfg = OmegaConf.create({"workers": "${times:2,4}"})
print(cfg.workers)Resolver names share process-wide state. Registering an existing name raises ValueError unless replacement is explicitly requested.
Block new keys and later mutation freeze-config
from omegaconf import OmegaConf
cfg = OmegaConf.create({"model": {"rate": 0.01}})
OmegaConf.set_struct(cfg, True)
OmegaConf.set_readonly(cfg, True)
# cfg.model.rtae = 0.1 raises ConfigAttributeError
# cfg.model.rate = 0.2 raises ReadonlyConfigErrorSet both flags after all intended merges. Struct mode rejects unknown keys, while read-only mode rejects changes to existing values.
Return plain collections or dataclass objects convert-output
plain = OmegaConf.to_container(cfg, resolve=True)
typed = OmegaConf.to_object(cfg)
yaml_text = OmegaConf.to_yaml(cfg, resolve=True)`to_container` returns built-in dictionaries and lists. `to_object` creates instances for structured nodes and also resolves interpolations.
Read and write a dotted path select-update-path
from omegaconf import OmegaConf
cfg = OmegaConf.create({"service": {"timeout": 10}})
timeout = OmegaConf.select(cfg, "service.timeout", default=30)
OmegaConf.update(cfg, "service.timeout", 15)
OmegaConf.update(cfg, "service.retries", 3, force_add=True)`select` can supply a default for an absent path. `force_add=True` deliberately bypasses struct restrictions when adding a new path.
Write and reload YAML save-config
from omegaconf import OmegaConf
OmegaConf.save(config=cfg, f="effective.yaml", resolve=True)
loaded = OmegaConf.load("effective.yaml")Saving with `resolve=True` writes resolved values rather than interpolation expressions. The YAML round trip does not preserve structured config type information.
Alternatives
| Package | Registry | Pick it when |
|---|---|---|
| pydantic-settings | PyPI | Choose it when Pydantic models and environment variables already define application settings. |
| dynaconf | PyPI | Choose it for named environments, layered files, and integrations with external secret stores. |
| hydra-core | PyPI | Choose it when the application also needs config groups, launch management, and parameter sweeps. |
| pyyaml | PyPI | Choose it when parsing and writing plain YAML is enough and no composition system is wanted. |
More utils guides
lru-cache · ajv · type-fest · p-limit · find-up · js-yaml · the whole shelf →
How this guide is made: grounded in the library's documentation, release notes, changelog, and issue history, on a fixed rubric — not a hands-on install of every release. The 50 most-downloaded entries are additionally install-verified in clean containers. Corrections: contact the desk.

