
Configuration Strategy: Settings and Secrets
Stop hard-coding your API keys. Learn how to use Pydantic Settings and environment variables to manage your application's configuration safely.
Configuration Strategy: Settings and Secrets
One of the most common ways apps get hacked is developers accidentally "committing" their API keys or database passwords to GitHub.
In a production-ready FastAPI app, your code should be generic. The specific details (like which database to connect to) should live in the Environment.
1. Environment Variables: The Source of Truth
An environment variable is a dynamic value that can affect the way running processes behave on a computer.
In your .env file (which you should NEVER commit to Git):
DATABASE_URL=postgresql://user:password@localhost/dbname
API_KEY=sk-123456789
DEBUG=True
2. Pydantic Settings: The Professional Way
FastAPI works perfectly with pydantic-settings. This allows you to define a Python class that automatically reads from your environment variables, converts them to the right type (e.g., a string to a Boolean), and group them together.
The Setup:
from pydantic_settings import BaseSettings
class Settings(BaseSettings):
app_name: str = "ShShell API"
admin_email: str
items_per_user: int = 50
class Config:
env_file = ".env"
settings = Settings()
Why this is superior:
- Validation: If you forget to set
admin_email, the app will crash immediately with a helpful error, rather than failing later when someone tries to send an email. - Type Conversion: If you set
DEBUG=Truein your.env, Pydantic converts that string into a PythonTrueBoolean. - Global Access: You can import
settingsanywhere in your app to access your configuration.
3. Handling Different Environments
Your configuration should change based on where your app is running.
/config
__init__.py
base.py # Common settings
dev.py # Debug = True, Mock DB
prod.py # Debug = False, Real RDS DB
You can choose which config to load using a simple environment flag like ENV_STATE=production.
4. The .env.example Pattern
Since you aren't committing your real .env file, how do other developers know what variables they need to set?
The Solution: Create a .env.example file that contains the variable names but dummy values.
# .env.example
DATABASE_URL=
STRIPE_API_KEY=
DEBUG=False
Visualizing the Config Flow
graph LR
A[".env File"] --> B["Pydantic BaseSettings"]
C["System Env Vars"] --> B
D["Default Values"] --> B
B --> E["Live App Configuration"]
E --> F["Database Connection"]
E --> G["Security Middleware"]
E --> H["Frontend URL"]
Summary
- Never hard-code secrets: Use environment variables.
- Use Pydantic Settings: It provides validation and type safety for your config.
- Environment Separation: Make sure your local testing doesn't touch your production database.
In the next lesson, we finish Module 3 with Exercises to test your architecture and configuration knowledge.
Exercise: The Missing Secret
Scenario: You just deployed your app to AWS, but it's crashing with a ValidationError saying SECRET_KEY is required.
- Where should you check first?
- Why is this crash actually a "Good Thing" compared to the app starting with a default, insecure secret?