Introduction
Configuration management is one of the most overlooked yet most critical parts of application architecture. Poor config design leads to security risks, deployment friction, and production instability.
This article explains where to store configuration files, how to structure them, and what to use in different scenarios—especially for modern Python and AI-based systems.
First Principle: Separate Code from Configuration
Never hardcode:
DATABASE_URL = "postgres://admin:password@localhost:5432/app"
API_KEY = "123456"
Configuration should be:
Types of Configurations
Before deciding where to store config, classify it:
| Type | Example | Should Be Version Controlled? | Should Be Secret? |
|---|
| Application Config | Port, debug mode | Yes | No |
| Infrastructure Config | Docker | Yes | No |
| Secrets | API keys, DB password | No | Yes |
| Runtime Environment | Production vs Dev | No | No |
Each type should be stored differently.
Where to Store Configuration Files
A. Inside the Project (Version Controlled)
Best for:
Application settings
Model parameters
Tool configuration
Non-sensitive defaults
Example structure:
project/
│
├── config/
│ ├── config.toml
│ ├── config.dev.toml
│ └── config.prod.toml
│
├── app/
│ └── main.py
Recommended format for application config:
TOML is widely used in modern Python ecosystems such as:
Environment Variables (.env File)
Best for:
Example. env:
DATABASE_URL=postgres://user:pass@localhost:5432/app
API_KEY=abc123
ENVIRONMENT=production
Used heavily with:
Important rule:
.env files should NOT be committed to Git.
Add to .gitignore.
Infrastructure Configuration
Infrastructure config should live:
infra/
│
├── docker-compose.yaml
├── k8s/
│ ├── deployment.yaml
│ └── service.yaml
Used in:
These should always be version controlled.
Cloud Secret Managers (Production)
For enterprise systems, secrets should NOT live in:
Git
Local files
Docker images
Use:
Secrets should be injected at runtime.
Recommended Structure for Modern Python
For an AI or MCP server:
mcp-server/
│
├── app/
│ ├── main.py
│ ├── settings.py
│
├── config/
│ ├── config.toml
│ ├── config.dev.toml
│ └── config.prod.toml
│
├── infra/
│ ├── docker-compose.yaml
│ └── k8s/
│
├── .env
├── .gitignore
Configuration Strategy by Environment
Development
Local config.dev.toml
.env for secrets
Simple file-based config
Staging
Production
What NOT to Do
Store passwords in Git
Store API keys inside YAML/TOML committed to repo
Hardcode environment-specific URLs
Mix infrastructure config with app config
Example: Clean Enterprise Setup
config.toml
[app]
name = "finance-mcp"
environment = "production"
[server]
port = 8000
[llm]
model = "llama3"
temperature = 0.2
.env
DATABASE_URL=postgres://...
OPENAI_API_KEY=...
settings.py
This separation:
Improves security
Improves deployment
Improves clarity
When to Store Config Outside the Project
In microservices or enterprise deployments:
Used when:
Multiple services share config
Runtime updates are required
Dynamic feature flags are needed
Quick Decision Guide
| Situation | Store Where |
|---|
| App settings | TOML/YAML inside project |
| Secrets | Environment variables / secret manager |
| Docker config | docker-compose.yaml |
| Kubernetes | YAML inside infra folder |
| CI/CD variables | Pipeline environment variables |
| Feature flags | Config file or remote config service |
Final Architecture Recommendation
Use a layered approach
TOML - structured application config
.env - secrets
YAML - infrastructure
Pydantic - validation layer
Secret Manager - production secrets
This gives:
Final Thought
Configuration storage is not about file format.
It is about:
Security
Environment separation
Maintainability
Deployment strategy
Good configuration design prevents 80% of production issues before they happen.