python
52 lines · 6 steps
Loading typed config from environment variables
Typed helpers parse environment variables into an immutable, cached configuration object.
Explained by
highlit
1import os
2from dataclasses import dataclass
3from functools import lru_cache
4
5
6def _get_bool(key: str, default: bool) -> bool:
7 value = os.environ.get(key)
8 if value is None:
9 return default
10 return value.strip().lower() in {"1", "true", "yes", "on"}
11
12
13def _get_int(key: str, default: int) -> int:
14 value = os.environ.get(key)
15 if value is None or not value.strip():
16 return default
17 try:
18 return int(value)
19 except ValueError as exc:
20 raise RuntimeError(f"{key} must be an integer, got {value!r}") from exc
21
22
23def _get_list(key: str, default: list[str]) -> list[str]:
24 value = os.environ.get(key)
25 if not value:
26 return default
27 return [item.strip() for item in value.split(",") if item.strip()]
28
29
30@dataclass(frozen=True)
31class Config:
32 database_url: str
33 port: int
34 debug: bool
35 max_connections: int
36 allowed_hosts: list[str]
37
38
39@lru_cache(maxsize=1)
40def load_config() -> Config:
41 try:
42 database_url = os.environ["DATABASE_URL"]
43 except KeyError as exc:
44 raise RuntimeError("DATABASE_URL is required") from exc
45
46 return Config(
47 database_url=database_url,
48 port=_get_int("PORT", 8000),
49 debug=_get_bool("DEBUG", False),
50 max_connections=_get_int("MAX_CONNECTIONS", 10),
51 allowed_hosts=_get_list("ALLOWED_HOSTS", ["localhost"]),
52 )
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1Centralizing env parsing into typed helpers keeps coercion logic consistent and testable.
- 2Failing loudly on missing or malformed required values catches misconfiguration at startup.
- 3A frozen dataclass plus lru_cache gives you an immutable config loaded exactly once.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import * as Joi from 'joi';
Validating env config at boot in NestJS
configuration
schema-validation
environment-variables
Intermediate
8 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
javascript
import { useState, useEffect, useCallback, useRef } from 'react'; const cache = new Map(); const inflight = new Map();
Building a stale-while-revalidate hook in React
caching
request-deduplication
custom-hooks
Advanced
10 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
php
<?php namespace App\Services;
Building a cached daily leaderboard in Laravel
caching
aggregation
eager-loading
Intermediate
9 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/loading-typed-config-from-environment-variables-explained-python-2269/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.