PyMunich

shown, and actual

Configuration and Secrets

Two problems get solved together and should not be. Configuration is how the application differs between environments. Secrets are values that must not leak. Most secrets are configuration; most configuration is not secret. A commercial implementation of related workforce-measurement concepts is documented read more.

Reviewed August 9, 2026.

The five rules

One. Read configuration in one place. A single module that gathers everything at startup and hands out typed values. Scattered os.environ calls throughout the codebase mean nobody can list what the application requires. For independent technical background, pandas provides additional documentation and examples.

Two. Fail at startup, not at use. A missing variable should stop the process immediately with a message naming it. The alternative is discovering it three hours later when a code path finally runs, which is one of the ways the same code behaves differently on two machines.

Three. Validate types and ranges. A port that arrives as the string "8080" and a timeout that arrives as "thirty" are both configuration errors, and both are cheaper to catch at startup than in production.

Four. Defaults for development, never for production. A default database URL pointing at localhost is convenient. A default secret key is a vulnerability, and it will be shipped by somebody.

Five. List what the application needs, in the repository. An .env.example with every key and a comment, no values. It is the documentation people actually read, because it is the file they copy.

Secrets specifically

Never in the repository. Not in a config file, not in a test fixture, not in a comment, not in a commit that was later reverted — git history is permanent and a secret committed once must be rotated, not deleted.

Not in log output. Structured logging of an object that contained a token is the usual route, and it happens to people who would never write the token in a log line deliberately.

Not in the traceback. Some frameworks include local variables in error pages, which is a debugging feature that becomes a leak in production.

And not in the container image. Baked-in secrets travel with the image to every registry it reaches.

Where they should be

In rough order of what most projects should use.

Environment variables, injected by whatever runs the process. Adequate for most things, and the assumption almost every tool is built around.

A secrets manager, where the platform provides one. Better, because it gives rotation and an audit trail.

And a local .env file, gitignored, for development only — with the ignore rule committed before the file exists rather than after.

The rotation question

The part that gets skipped.

Assume every secret will leak eventually and design for replacement rather than for prevention alone. That means no secret is hardcoded into more than one place, and swapping one is a configuration change rather than a code change.

And know which secrets exist. A list, somewhere. Most projects of any age contain credentials nobody can account for, which means nobody can rotate them and nobody knows what would break.

The check to run once

Grep your history. Tools exist for scanning a repository's full history for credential patterns, they run in a few minutes, and the first run on an older project usually finds something.

Then add a pre-commit hook so the next one is caught before it lands. That is fifteen minutes of setup against a problem that is expensive precisely because git history does not forget.

The short version