mrkeyoor.com_
Sun 20 Sept 02:44 UTC
PyPIUtilsupdated 19 Sept 2026

pydantic-settings review

pydantic-settings 2.15.0 builds a validated Pydantic model from command-line arguments, constructor values, environment variables, dotenv files, mounted secret files, config files, or optional cloud secret sources. It handles source precedence and naming, while Pydantic handles field parsing and validation. Release 2.15.0 makes case_sensitive apply to constructor and JSON, TOML, and YAML inputs; adds PYDANTIC_SETTINGS_DEBUG; supports nested TOML table roots and packaged config resources; and shows environment names in generated CLI help. It also warns on unresolved forward references and fixes UTF-8 secret reads plus nested-secret symlink containment. Our Python 3.12 import passed and py.typed was present.

Verdict

pydantic-settings 2.15.0 installed in 0.4 seconds, used 8 MB across 7 packages, imported in 0.67 seconds, and returned 0 pip-audit findings in our sandbox. It earns its place when a Pydantic application needs validated startup configuration from several sources; direct environment reads are clearer for a few scalar values, and PYDANTIC_SETTINGS_DEBUG must stay away from production logs.

We installed it

Lab card: what happened when we installed pydantic-settingsScreenshot of pydantic-settings documentation
Install✓ · 0.4s7 packages on disk · 8 MB
Importimport pydantic_settings in 0.67s · pure Python · py.typed · requires Python >=3.10
Known vulns0(pip-audit)

Answers from our run

Does pydantic-settings install cleanly?

Yes. In a fresh container with an empty cache, pip install pydantic-settings finished in 0.4s, leaving 7 packages and 8 MB on disk. pip-audit reported no known vulnerabilities.

What does pydantic-settings need to run?

Python >=3.10, and nothing compiled: it is pure Python. In our run import pydantic_settings succeeded in 0.67s, and the package ships py.typed for type checkers.

pydantic-settings or environs: which should you use?

environs: Use it for a smaller Marshmallow-based API centered on environment and dotenv values. pydantic-settings 2.15.0 installed in 0.4 seconds, used 8 MB across 7 packages, imported in 0.67 seconds, and returned 0 pip-audit findings in our sandbox.

When should you not use pydantic-settings?

The program reads three scalar environment values and otherwise has no Pydantic dependency. os.environ with explicit conversions is easier to audit.

API stability4/5The 2.x line continues to center on BaseSettings, SettingsConfigDict, settings_customise_sources(), and explicit source classes. Version 2.15 retains those entry points but changes case-insensitive matching for constructor and config-file data, emits a new warning for unresolved forward references, and turns one strict-field parsing failure into ValidationError. These fixes can still break warning-as-error tests or code that relied on mixed-case input being discarded.
Docs5/5The official manual specifies source priority, aliases, prefixes, nested delimiters, dotenv search depth, secret directories, custom sources, decoding controls, command-line generation, TOML and YAML files, and three cloud secret systems. It includes exact behavior for missing files and unmatched dotenv keys. The 2.15 section also warns that source-debug logs can expose secret values, which is the operational detail most quick starts would omit.
Maintenance5/5GitHub showed an unarchived repository pushed on August 23, 2026, with 1,433 stars and 34 open issues and pull requests. Release 2.15.0 shipped on August 7 with source diagnostics, packaged-resource support, CLI help changes, Windows environment fixes, UTF-8 secret reads, cloud permission work, and parsing corrections. The preceding 2.14.2 security release closed an out-of-directory symlink read in nested secret handling.
Ecosystem4/5PyPI Stats counted 113,196,156 downloads in its recent weekly window. The base package plugs into Pydantic models and python-dotenv, while declared extras cover AWS Secrets Manager, Azure Key Vault, Google Secret Manager, TOML, and YAML. Generated CLI support can reuse the same model. Projects outside Pydantic must accept its validation rules and installed core packages just to load configuration, which limits the benefit of this reach.

Use it if

  • The application already uses Pydantic and should fail startup when a required setting is missing or has the wrong shape.
  • Local dotenv files, deployment environment variables, and mounted secret files need one documented priority order.
  • Nested models should map to names such as APP_DATABASE__HOST without a separate configuration object.
  • A typed settings model should also drive command-line flags, TOML or YAML input, or a cloud secret source.
Skip it if

Setup reality

We installed pydantic-settings 2.15.0 without a cache in an unprivileged Python 3.12 Bookworm container. It completed in 0.4 seconds and left 7 packages using 8 MB. The measured package metadata listed 9 direct dependencies, Python 3.10 or newer, pure Python code, py.typed, and the MIT License. pip-audit found 0 known vulnerabilities. import pydantic_settings succeeded in 0.67 seconds. Pydantic and python-dotenv are part of this base footprint.

Default priority runs from CLI arguments, when enabled, to constructor values, environment variables, dotenv, secret files, then model defaults. Real environment values beat .env values. A relative env_file starts at the current working directory; env_file_depth can search a configured number of parent levels. Complex fields expect JSON text. Aliases and prefixes change the names every source searches, and an unmatched dotenv key can raise ValidationError under the default extra='forbid'.

Version 2.15 adds PYDANTIC_SETTINGS_DEBUG=1. With DEBUG logging enabled, it prints every source in priority order, the values each source returned, which value won, and which files were checked. Those dictionaries may contain passwords and tokens, so use the flag only in a trusted debugging session and turn it off afterward. settings_customise_sources() can reorder or replace sources; the returned tuple runs from highest to lowest priority, so a wrong order silently changes configuration.

A secrets directory maps filenames to field values. Version 2.15 reads them as UTF-8 and blocks NestedSecretsSettingsSource symlinks that point outside secrets_dir. AWS, Azure, Google, TOML, and YAML sources require extras beyond our 7-package base install, and cloud sources may perform network I/O while constructing settings. Build one settings instance during startup or cache it instead of repeating file and network work for every request. case_sensitive now affects constructor and config-file inputs too, so mixed-case keys that were ignored before 2.15 may start populating fields.

Patterns

Validate startup environment values load-environment

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(env_prefix='APP_')

    database_url: str
    workers: int = 4
    debug: bool = False

settings = Settings()

APP_DATABASE_URL is required. Pydantic converts APP_WORKERS and APP_DEBUG, then raises ValidationError if conversion fails.

Read a dotenv file with an explicit encoding load-dotenv

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file='.env',
        env_file_encoding='utf-8',
        extra='ignore',
    )

    api_url: str

settings = Settings()

Real environment variables override .env values. extra='ignore' prevents unrelated dotenv keys from failing model construction.

Search parent directories for .env search-parent-dotenv

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_file='.env',
        env_file_depth=2,
    )

    database_url: str

env_file_depth=2 checks at most 2 parent levels when the relative file is absent from the current working directory.

Map nested environment names load-nested-model

from pydantic import BaseModel
from pydantic_settings import BaseSettings, SettingsConfigDict

class Database(BaseModel):
    host: str
    port: int = 5432

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        env_prefix='APP_',
        env_nested_delimiter='__',
    )
    database: Database

# APP_DATABASE__HOST=db.internal

The double separator turns APP_DATABASE__HOST into database.host. Unknown field paths are not expanded.

Accept a comma-separated environment list parse-comma-list

from typing import Annotated, Any
from pydantic import BeforeValidator
from pydantic_settings import BaseSettings, NoDecode

def split_csv(value: Any) -> Any:
    return value.split(',') if isinstance(value, str) else value

CsvList = Annotated[list[str], NoDecode, BeforeValidator(split_csv)]

class Settings(BaseSettings):
    allowed_hosts: CsvList

NoDecode stops the default JSON parser. Without it, a value such as api.local,admin.local is invalid JSON.

Read mounted secret files load-docker-secrets

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(secrets_dir='/run/secrets')

    database_password: str

settings = Settings()

/run/secrets/database_password supplies the field. Environment and dotenv values have higher default priority than secret files.

Let environment beat constructor values change-source-priority

from pydantic_settings import BaseSettings, PydanticBaseSettingsSource

class Settings(BaseSettings):
    endpoint: str

    @classmethod
    def settings_customise_sources(
        cls,
        settings_cls: type[BaseSettings],
        init_settings: PydanticBaseSettingsSource,
        env_settings: PydanticBaseSettingsSource,
        dotenv_settings: PydanticBaseSettingsSource,
        file_secret_settings: PydanticBaseSettingsSource,
    ):
        return env_settings, init_settings, dotenv_settings, file_secret_settings

The tuple is ordered from highest to lowest priority. This example intentionally lets an environment value replace the same constructor keyword.

Trace which source supplied each value debug-source-resolution

import logging
import os

logging.basicConfig(level=logging.DEBUG)
os.environ['PYDANTIC_SETTINGS_DEBUG'] = '1'

settings = Settings()

Version 2.15 logs each source dictionary and winning values. The output may include secrets, so do not leave this enabled in production.

Turn settings fields into command-line flags generate-cli

from pydantic_settings import BaseSettings, SettingsConfigDict

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        cli_parse_args=True,
        cli_show_env_vars=True,
        env_prefix='APP_',
    )

    host: str = '127.0.0.1'
    port: int = 8000

settings = Settings()

CLI arguments are the highest-priority source by default. Version 2.15 can show the corresponding environment names in help output.

Use one TOML table as the settings root load-toml-table

from pydantic_settings import (
    BaseSettings,
    PydanticBaseSettingsSource,
    SettingsConfigDict,
    TomlConfigSettingsSource,
)

class Settings(BaseSettings):
    model_config = SettingsConfigDict(
        toml_file='config.toml',
        toml_table_header=('service',),
    )
    port: int

    @classmethod
    def settings_customise_sources(cls, settings_cls, *sources):
        return (TomlConfigSettingsSource(settings_cls),)

Version 2.15 lets TomlConfigSettingsSource root values at [service] instead of reading the whole file as the model.

Add AWS Secrets Manager as a source load-aws-secret

from pydantic_settings import (
    AWSSecretsManagerSettingsSource,
    BaseSettings,
)

class Settings(BaseSettings):
    database_password: str

    @classmethod
    def settings_customise_sources(cls, settings_cls, *sources):
        aws = AWSSecretsManagerSettingsSource(
            settings_cls,
            secret_id='prod/my-service',
        )
        return (*sources, aws)

Install the aws-secrets-manager extra and provide normal AWS credentials. This source can make a network request during Settings construction.

Create one settings instance per process cache-settings

from functools import lru_cache

@lru_cache
def get_settings() -> Settings:
    return Settings()

settings = get_settings()

BaseSettings reads its sources during construction. Caching avoids repeated dotenv, secret-file, and optional cloud-source work on every request.

Alternatives

PackageRegistryPick it when
environsPyPIUse it for a smaller Marshmallow-based API centered on environment and dotenv values.
dynaconfPyPIUse it when named environments, layered file merging, remote stores, and reload behavior define the configuration system.
python-decouplePyPIUse it for a compact Django-friendly split between environment values, local config files, and code defaults.

More utils guides

lru-cache · type-fest · ajv · 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.