environs is a library for reading environment variables from a .env file with type support. It is an evolution of python-dotenv: rather than just loading strings, it returns proper types and raises a clear error if a variable is not set.
Why Not python-dotenv
# python-dotenv + os.getenv:
from dotenv import load_dotenv
import os
load_dotenv()
api_key = os.getenv("ANTHROPIC_API_KEY") # string or None
debug = os.getenv("DEBUG") # "True" — this is a string, not a bool!
port = int(os.getenv("PORT", "8000")) # you have to convert manually
# If a variable is not set — None, and the program crashes somewhere deep
# with a confusing AttributeError: 'NoneType'
# environs:
from environs import Env
env = Env()
env.read_env()
api_key = env.str("ANTHROPIC_API_KEY") # string — explicit
debug = env.bool("DEBUG", False) # real bool
port = env.int("PORT", 8000) # real int
# If ANTHROPIC_API_KEY is not set — EnvError is raised immediately on startup:
# environs.EnvError: 'ANTHROPIC_API_KEY' not set or empty
With environs, types are declared explicitly and errors surface immediately at startup — not in the middle of program execution.
Installation
uv add environs
Basic Usage
from environs import Env
env = Env()
env.read_env() # reads .env from the current directory
# Strings
api_key = env.str("ANTHROPIC_API_KEY")
base_url = env.url("API_BASE_URL")
# Numbers
port = env.int("PORT", 8000) # with a default
timeout = env.float("TIMEOUT", 30.0)
# Booleans
debug = env.bool("DEBUG", False) # "true", "1", "yes", "on" → True
# Lists
hosts = env.list("ALLOWED_HOSTS", []) # "a,b,c" → ["a", "b", "c"]
Required and Optional Variables
# Required — raises EnvError if not set:
api_key = env.str("ANTHROPIC_API_KEY")
# Optional — returns the default:
model = env.str("MODEL", "claude-sonnet-4-6")
max_tokens = env.int("MAX_TOKENS", 2048)
Always make a variable required if the program cannot function without it. An explicit error at startup is far better than a mysterious crash mid-execution.
.env File
ANTHROPIC_API_KEY=sk-ant-api03-...
MODEL=claude-sonnet-4-6
MAX_TOKENS=2048
DEBUG=false
Rules for .env:
- One key per line
- No spaces around =
- Values without quotes (you can use them, but it’s not necessary)
- Comments with #
.env in .gitignore — Required
The .env file contains secrets — never commit it under any circumstances.
# .gitignore
.env
.env.local
.env.*.local
For your team, create a .env.example with empty values and commit that instead:
# .env.example — safe to commit
ANTHROPIC_API_KEY=
MODEL=claude-sonnet-4-6
MAX_TOKENS=2048
DEBUG=false
config.py — A Single Source of Truth for Configuration
Best practice: keep all configuration in a dedicated file:
# config.py
from environs import Env
env = Env()
env.read_env()
API_KEY = env.str("ANTHROPIC_API_KEY")
MODEL = env.str("MODEL", "claude-sonnet-4-6")
MAX_TOKENS = env.int("MAX_TOKENS", 2048)
DEBUG = env.bool("DEBUG", False)
All other files import from config.py — no duplicated env loading.
# main.py
from config import API_KEY, MODEL, MAX_TOKENS
💬 Comments (0)
No comments yet
Be the first to share your opinion about this article!