Konfig
Settings management, pluggable secrets, and run-scoped logging for Python applications.
Konfig provides three foundational capabilities every Python application needs, with an optional lightweight app lifecycle context manager that ties them together. It is a clean-sheet replacement for dtPyAppFramework.
Features
- Layered settings with system/user/env/runtime precedence and persistent writes
- Pluggable secrets with OS keyring, AES-encrypted file, and AWS Secrets Manager backends
- Run-scoped logging with historical retention, structured JSON mode, and stdio-safe output
- Optional centralised log forwarding: one nominated collector gathers every container's logs over pinned TLS, discovered automatically through the shared secrets store
- Platform-aware defaults for config, data, and log directories (macOS, Linux, Windows)
- Optional app lifecycle via a sync/async context manager — no inheritance required
- Python 3.10+
Installation
pip install konfig
For AWS Secrets Manager support:
pip install konfig[aws]
Secrets
AWS Secrets Manager (designated secret)
Point konfig at a single AWS secret that holds a JSON bundle of your secrets (the secret must already exist):
export KONFIG_AWS_SECRETS_MANAGER=arn:aws:secretsmanager:eu-west-1:123456789012:secret:myapp/secrets-AbCdEf
from konfig import Secrets
secrets = Secrets() # env var selects the AWS bundle backend
api_key = secrets.get("api_key")
secrets.set("api_key", "sk-new") # read-modify-write back to the bundle
Requires pip install konfig[aws].
AWS Secrets Manager settings document (KONFIG_AWS_SETTINGS)
Deliver an application's entire configuration as one JSON document held in a single Secrets Manager secret — no config file or per-setting environment variables needed in the task definition:
export KONFIG_AWS_SETTINGS=arn:aws:secretsmanager:eu-west-1:123456789012:secret:myapp/settings-AbCdEf
The secret's SecretString must be a JSON object holding the same nested
settings tree a config file would. A plain secret name is also accepted; the
region then comes from the default AWS provider chain (with an ARN it is
taken from the ARN). An equivalent constructor argument exists for
programmatic use — Settings(aws_settings=...) — with the environment
variable winning when both are set. Requires pip install konfig[aws].
Precedence (highest to lowest):
runtime -> env vars -> AWS settings -> user file -> system file -> defaults
— environment variables remain the operator's immediate per-container
override, while the AWS document overrides anything baked into the image.
Behaviour:
- Read-only.
settings.set(...)keeps writing to the runtime layer or config files exactly as before. - Fail fast. A missing/unreadable secret, non-JSON payload, or non-object top level raises at startup rather than silently degrading to defaults. Error messages name the secret, never its payload.
- Fetched once. The document is read at construction and only re-fetched
by
settings.reload(); there is no background polling. - Composes with secrets. Values in the document may be
secret://URIs, resolved as usual by the active secrets backend.
This is independent of KONFIG_AWS_SECRETS_MANAGER. Pointing both at the
same secret works, but keeping configuration and secret material in separate
Secrets Manager entries is recommended so IAM can distinguish "may read
config" from "may read credentials".
First boot on AWS: seeded stores
When konfig starts against empty stores (an empty or whitespace-only
SecretString, or a bare {}), it writes a template for the operator instead
of leaving them to transcribe documentation:
- The
KONFIG_AWS_SETTINGSsettings secret is seeded with the application's defaults tree as pretty-printed JSON. Startup continues with reads resolving exactly as if the layer were absent. - The
KONFIG_AWS_SECRETS_MANAGERbundle secret is seeded with a"CHANGEME"placeholder for everysecret://<name>reference in the effective settings. Resolving an unpopulated placeholder logs a warning naming the key.AppContextruns this automatically at startup; when composingSettingsandSecretsyourself, callsecrets.seed_from(settings).
The intended first-boot flow: create the two (empty) secrets, grant
secretsmanager:PutSecretValue on them for first boot, start once, edit the
seeded documents, restart — and optionally drop the write grant again.
Seeding never touches a non-empty store (malformed payloads keep failing
fast, and partial documents are never merged into), never creates secrets,
and a failed seed write (for example AccessDenied under a read-only role)
only logs a warning. Concurrent replicas racing the first boot are benign:
every writer writes identical content. Operators who want no write attempt at
all can disable seeding outright with KONFIG_AWS_SEED=false.
Running the LocalStack integration tests
The AWS integrations have opt-in integration tests that run against a local LocalStack container (no AWS account needed). They auto-skip when LocalStack is not running, so they never affect the normal test run.
docker compose up -d # start LocalStack
pip install -e ".[dev,aws]" # boto3 + dev tools
pytest -m localstack # run only the integration test
docker compose down # stop LocalStack
The tests look for LocalStack at http://127.0.0.1:4566, the port docker-compose.yml
publishes. If it is published somewhere else, point the tests at it with
KONFIG_TEST_LOCALSTACK_URL (an http(s) URL with a host and a port):
KONFIG_TEST_LOCALSTACK_URL=http://127.0.0.1:24566 pytest -m localstack
Quick Start
from konfig import AppContext
with AppContext(
name="My Application",
version="1.0.0",
config_file="config.yaml",
env_prefix="MYAPP",
) as ctx:
host = ctx.settings.get("database.host", "localhost")
api_key = ctx.secrets.get("api_key")
ctx.logger.info("Starting with host=%s", host)
For async applications:
async with AppContext(name="My Server", version="2.0.0") as ctx:
await run_server(ctx.settings)
Config file format
The config file format is chosen by the KONFIG_CONFIG_FORMAT environment variable
(yaml, json, or sqlite). When unset, the format is detected from the file extension,
defaulting to YAML. Reading, updating, and creating settings work in every format.
(TOML config files are still supported by extension detection, but are read-only and
cannot be selected via KONFIG_CONFIG_FORMAT.)
export KONFIG_CONFIG_FORMAT=sqlite # store settings in a SQLite database file
from konfig import Settings
settings = Settings(config_file="config.db")
settings.set("database.host", "localhost", persist="user") # written to SQLite
settings.set("debug", True) # omit persist: in-memory only
host = settings.get("database.host")
Centralised log forwarding
To collect every container's logs in one place, nominate one instance as the collector and turn on forwarding everywhere else. Each instance keeps its own local logs as before:
# On the collector (needs a persistent volume at its log directory)
KONFIG_LOG_COLLECTOR=true
KONFIG_LOG_COLLECTOR_ADVERTISE=log-collector:9020
# On every other instance
KONFIG_LOG_CENTRAL=true
KONFIG_LOG_INSTANCE_LABEL=worker-3 # optional
AppContext does the rest. The collector generates a TLS certificate and an access token and
publishes them in the shared secrets store, senders discover them, and every record lands, tagged
with its instance, in <log_dir>/central/latest/central.log on the collector. See
Centralised Log Forwarding.
Each subsystem (Settings, Secrets, LogManager) can also be used independently. See the full documentation in the docs/ directory:
- Settings Guide
- Secrets Guide
- Logging Guide
- AppContext Guide
- Platform Paths
- Configuration Reference
- API Reference
Samples
Working examples are provided in the samples/ directory:
| File | Description |
|---|---|
basic_settings.py |
Config files, defaults, env vars, overrides |
secrets_usage.py |
Store, retrieve, and delete secrets |
logging_demo.py |
Run-scoped logging with retention |
app_context.py |
Full lifecycle with all subsystems |
async_app.py |
Async context manager usage |
custom_backend.py |
Implementing a custom SecretBackend |
central_logging.py |
Centralised log forwarding: collector and sender roles |
Development
CI installs the development tools from a hash-locked requirements file and then konfig
itself. Do the same locally to get exactly the versions CI tests with (the lock covers
Linux, macOS and Windows on Python 3.10 to 3.13, and includes the dev and aws extras):
python -m pip install --require-hashes --only-binary :all: -r requirements/dev.txt
python -m pip install --no-deps --no-build-isolation -e .
pip install -e ".[dev,aws]" still works when you do not need the locked versions.
The lock files are generated from the .in files beside them, together with
pyproject.toml, by uv 0.13.6 (the version CI uses).
Regenerate them from the repository root after changing a dependency in pyproject.toml or
a .in file:
uv pip compile --universal --generate-hashes --python-version 3.10 requirements/build.in -o requirements/build.txt
uv pip compile --universal --generate-hashes --python-version 3.10 pyproject.toml requirements/dev.in --extra dev --extra aws -o requirements/dev.txt
uv keeps the versions already in the lock files; add --upgrade (or
--upgrade-package <name>) to move them on. CI regenerates both files and fails if the
result differs from what is committed.
The GitHub Actions in .github/workflows/ are pinned to full commit SHAs with the tag as a
trailing comment; Dependabot (.github/dependabot.yml) proposes updates to them weekly, as
one grouped pull request, and never touches the lock files.
pytest
pytest --cov=konfig
mypy src/konfig
black src/ tests/
isort src/ tests/
License
MIT License. See LICENSE for details.
Metadata
Release files for cognisn-konfig 0.5.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| cognisn_konfig-0.5.0.tar.gz | 186.7 kB | With provenance | Details for cognisn_konfig-0.5.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| cognisn_konfig-0.5.0-py3-none-any.whl | Python 3 | none | any | Details for cognisn_konfig-0.5.0-py3-none-any.whl |
Total release size: 258.6 kB
Release files / cognisn_konfig-0.5.0.tar.gz
| Download URL | cognisn_konfig-0.5.0.tar.gz |
|---|---|
| Size | 186.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
34e28552ca87645714b48a54c6e6e9dab775ab8a2a732ae1f39a42d058bf323f
|
|
BLAKE2b-256 checksum How to use checksums |
d43025f9b12f6ba5cbbcf1c00c17feba5d48ea59f2ea289a856e1548db2d52e2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logRelease files / cognisn_konfig-0.5.0-py3-none-any.whl
| Download URL | cognisn_konfig-0.5.0-py3-none-any.whl |
|---|---|
| Size | 71.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
73797f62a4a53c96e2f7c957d900ec3885dd845820105972d5f0e871e106f44d
|
|
BLAKE2b-256 checksum How to use checksums |
61fb67072e36630e93ea15284ae72930c3b7e0b7ca454b5cb67541c9eec4a702
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logSecurity for cognisn-konfig 0.5.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for cognisn_konfig-0.5.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Nov 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.