Learning Python - Configuration, Secrets & Environment Management
Series/Learn Python/Episode 11
Episode 11 of 23

Learning Python - Configuration, Secrets & Environment Management

This episode covers secure application configuration: Twelve-Factor config through environment variables, loading .env with python-dotenv, tools like dynaconf and pydantic settings, and best practices for managing secrets so they never get committed to Git.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

Configuration and secrets are the most often overlooked but most critical parts. Episode 11 covers how to manage application configuration correctly: separating configuration from code, loading it from the environment, and protecting secrets so they never leak into Git.

We'll learn Twelve-Factor config, python-dotenv, modern tools like dynaconf and pydantic-settings, and the best practices adopted by production teams around the world.

Twelve-Factor Config

The Basic Principle

The Twelve-Factor App is a methodology for building modern applications. Its third principle states: store configuration in the environment. Configuration is everything that differs between deployments — database URLs, credentials, and feature toggles.

PythonMembaca konfigurasi dari environment
import os
 
host = os.getenv("DATABASE_HOST", "localhost")
port = os.getenv("DATABASE_PORT", "5432")
 
print(host, port)

os.getenv("DATABASE_HOST", "localhost") reads an environment variable with a default value. Configuration held in the environment can change without changing code — the foundation of flexible deployment.

Why Not in Code

Storing configuration in code causes problems: code can't be reused across environments, and secrets get committed to Git along with it. With the environment, dev and production configuration differ without changing a single line of source code.

Using python-dotenv

Loading a .env File

During local development, typing export over and over is impractical. python-dotenv loads a .env file into the environment:

Install python-dotenv
pip install python-dotenv
PythonMemuat .env
from dotenv import load_dotenv
import os
 
load_dotenv()
 
database_url = os.getenv("DATABASE_URL")
print(database_url)

load_dotenv() reads the .env file in the working directory and puts its contents into the environment. After that os.getenv just works. This speeds up local setup without sacrificing consistency.

An Example .env File

A .env file contains key-value pairs:

Contoh file .env
DATABASE_URL=postgresql://user:pass@localhost/db
API_KEY=secret-anda-jangan-di-commit
LOG_LEVEL=INFO

This .env file must be in .gitignore — we'll cover how in the secrets section. Its contents are specific to each developer and must not be shared through Git.

dynaconf and pydantic-settings

dynaconf: Multi-File Configuration

dynaconf provides layered configuration with support for many formats:

Install dynaconf
pip install dynaconf
PythonMenggunakan dynaconf
from dynaconf import Dynaconf
 
settings = Dynaconf(
    settings_files=["settings.toml", ".env"],
    envvar_prefix="APP",
)
 
print(settings.host)
print(settings.get("port", 8000))

Dynaconf(settings_files=["settings.toml", ".env"]) loads configuration from several sources with priority. envvar_prefix="APP" means environment variables like APP_PORT are also recognized. dynaconf suits applications with many configuration layers.

pydantic-settings: Automatic Validation

pydantic-settings combines pydantic with the environment:

Install pydantic-settings
pip install pydantic-settings
PythonSettings dengan pydantic
from pydantic_settings import BaseSettings, SettingsConfigDict
 
class Settings(BaseSettings):
    app_name: str
    database_url: str
    debug: bool = False
 
    model_config = SettingsConfigDict(env_file=".env")
 
settings = Settings()
print(settings.app_name)

class Settings(BaseSettings) defines configuration with types and automatic validation. model_config points to the .env file. If database_url is missing or the wrong type, the application fails at startup — much better than failing halfway through.

Secret Management Best Practices

.gitignore for Secrets

The first rule of secret management: never commit them to Git:

Isi .gitignore
.env
*.env
!.env.example

The .env and *.env lines exclude secret files from Git. The exception !.env.example still allows a template without secret values to be committed. This is the standard practice in all professional Python projects.

Using .env.example

Commit an empty template so the team knows which variables are needed:

.env.example yang di-commit
DATABASE_URL=postgresql://user:pass@localhost/db
API_KEY=ganti-dengan-key-anda
LOG_LEVEL=INFO

The .env.example file contains variable names with example or placeholder values. New team members just copy it to .env and fill in real values. This template is safe to commit because it holds no secrets.

Managing Secrets in Production

In production, secrets should be managed by dedicated systems, not in files:

  • Environment variables from the deployment platform.
  • Secret managers like Vault, AWS Secrets Manager, or cloud native options.
  • CI/CD secrets for automated pipelines.

The golden rule: secrets are injected at runtime, never written in code or images. You'll practice this during deployment in episode 20.

Closing

Key takeaways:

  • Twelve-Factor stores configuration in the environment, not in code.
  • python-dotenv loads .env files for local development.
  • dynaconf offers layered multi-file configuration.
  • pydantic-settings provides type validation at startup.
  • .env files and secrets must be in .gitignore.
  • Commit .env.example as a template without secret values.

In the next episode, episode 12, we'll cover basic networking and HTTP clients — modern usage of requests, httpx for sync and async, setting up retries, timeouts, and connection pooling, plus an overview of WSGI servers with Gunicorn and ASGI with Uvicorn. Your project starts communicating with the outside world!

Learning Python - Configuration, Secrets & Environment Management | Learn Python