Environment Configuration Skill
Overview
This skill provides comprehensive guidance for managing environment configurations, secrets, and environment variables in Python projects using UV (the modern Python package and project manager). It covers secure configuration patterns, multi-environment setups, .env file management, and secrets handling with encryption support.
Environment configuration is critical for separating configuration from code (12-factor app principles), managing secrets securely across environments, preventing credential leaks, and supporting team collaboration.
When to Use This Skill
Use this skill when you need to:
- Set up environment configuration for a new Python project
- Implement secure secrets management
- Configure multi-environment setups (dev/staging/prod)
- Migrate from hardcoded configs to environment variables
- Audit existing configuration for security issues
- Standardize configuration across team projects
- Set up UV-based Python project with proper config management
Core Principles
1. Never Hardcode Secrets
- All API keys, passwords, tokens go in environment variables or encrypted secrets
- Configuration files with secrets must be in .gitignore
- Use templates for sharing structure, not actual secrets
2. Separate by Environment
- Different configurations for development, staging, production
- Environment-specific .env files (.env.development, .env.production)
- Clear naming conventions for environment variables
3. Fail Securely
- Validate required environment variables on startup
- Provide clear error messages for missing configuration
- Use sensible defaults only for non-sensitive values
4. Use UV for Dependency Management
- UV provides fast, reliable Python package management
- Replaces pip, pip-tools, virtualenv, and more
- Ensures reproducible environments across machines
5. Document Everything
- Template files show structure without exposing secrets
- README explains required variables and how to set them
- Comments describe purpose and format of variables
UV Setup
Installing UV
# macOS/Linux
curl -LsSf https://astral.sh/uv/install.sh | sh
# Or with pip
pip install uv
# Verify installation
uv --version
Initialize UV Project
# Create new project
uv init my-project
cd my-project
# Create virtual environment
uv venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
# Add dependencies
uv add python-dotenv cryptography pydantic
# Add dev dependencies
uv add --dev pytest pytest-env black ruff
Environment Configuration Workflow
Phase 1: Project Setup
1. Create Project Structure
# Initialize UV project
uv init your-project-name
cd your-project-name
uv venv
source .venv/bin/activate
2. Install Configuration Dependencies
uv add python-dotenv # For .env file loading
uv add cryptography # For secrets encryption (optional)
uv add pydantic # For config validation (optional)
uv add --dev pytest pytest-env
3. Create Configuration Files
Essential files to create:
.env.template- Template showing required variables (commit this).env- Actual secrets (add to .gitignore).env.development- Development-specific config.env.production- Production-specific configconfig.py- Configuration loading module
4. Update .gitignore
# Add to .gitignore
cat >> .gitignore << 'EOF'
# Environment files
.env
.env.local
.env.*.local
secrets.json
# UV
.venv/
__pycache__/
*.pyc
.pytest_cache/
.ruff_cache/
EOF
Phase 2: Create Configuration Templates
1. Create .env.template
# .env.template - Commit this file
# Copy to .env and fill in actual values
# Application Settings
APP_NAME=MyApp
APP_ENV=development
DEBUG=true
LOG_LEVEL=INFO
# Database Configuration
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
DATABASE_POOL_SIZE=5
# API Keys (Replace with actual keys)
ANTHROPIC_API_KEY=sk-ant-api03-xxx
OPENAI_API_KEY=sk-xxx
OPENROUTER_API_KEY=sk-or-v1-xxx
# Security
SECRET_KEY=generate-random-secret-key-here
JWT_SECRET=another-random-secret
# Feature Flags
ENABLE_ANALYTICS=false
ENABLE_CACHING=true
2. Create Config Loading Module
Create config.py - see references/api-reference.md for complete implementation:
import os
from pathlib import Path
from dotenv import load_dotenv
class ConfigError(Exception):
"""Raised when required configuration is missing."""
pass
class Config:
"""Application configuration from environment variables."""
def __init__(self, env: str = None):
self.env = env or os.getenv('APP_ENV', 'development')
self._load_env_file()
self._validate_required()
def _load_env_file(self):
"""Load appropriate .env file based on environment."""
env_file = Path(f'.env.{self.env}')
if env_file.exists():
load_dotenv(env_file, override=True)
if Path('.env').exists():
load_dotenv('.env', override=False)
@property
def app_name(self) -> str:
return os.getenv('APP_NAME', 'MyApp')
@property
def debug(self) -> bool:
return os.getenv('DEBUG', 'false').lower() in ('true', '1', 'yes')
# Add more properties as needed...
# Global config instance
config = Config()
For complete Config class with all properties and validation, see references/api-reference.md.
3. Use Config in Application
from config import config
def main():
print(f"Starting {config.app_name} in {config.app_env} mode")
if config.anthropic_api_key:
# Use API key
print("✓ API key loaded")
Phase 3: Multi-Environment Setup
1. Create Environment-Specific Files
.env.development:
APP_ENV=development
DEBUG=true
LOG_LEVEL=DEBUG
DATABASE_URL=postgresql://localhost:5432/myapp_dev
.env.production:
APP_ENV=production
DEBUG=false
LOG_LEVEL=WARNING
DATABASE_URL=postgresql://prod-host:5432/myapp_prod
SECRET_KEY=super-secure-random-key
2. Switch Between Environments
# Development (default)
uv run python main.py
# Production
export APP_ENV=production
uv run python main.py
Phase 4: Secrets Management
1. Using JSON Secrets (Alternative Pattern)
Create secrets_template.json:
{
"anthropic_api_key": "sk-ant-api03-xxx",
"openai_api_key": "sk-xxx",
"database_password": "your-password-here",
"comment": "Copy to secrets.json and fill in real values"
}
2. Load JSON Secrets
See references/api-reference.md for complete implementation:
import json
from pathlib import Path
def load_secrets(secrets_file: str = 'secrets.json') -> dict:
"""Load secrets from JSON with fallback to env vars."""
if Path(secrets_file).exists():
return json.load(open(secrets_file))
# Fallback to environment variables
return {
'anthropic_api_key': os.getenv('ANTHROPIC_API_KEY', '')
}
3. Encrypted Secrets
For encryption utilities and advanced secrets management, see:
references/advanced-topics.md- Encryption, rotation, auditingscripts/env_helper.py- Encryption/decryption utilities
Configuration Validation
Using Pydantic for Type-Safe Config
from pydantic import BaseSettings, Field, validator
class Settings(BaseSettings):
app_name: str = Field(default='MyApp', env='APP_NAME')
app_env: str = Field(default='development', env='APP_ENV')
database_url: str = Field(..., env='DATABASE_URL') # Required
@validator('app_env')
def validate_env(cls, v):
allowed = ['development', 'staging', 'production']
if v not in allowed:
raise ValueError(f'app_env must be one of {allowed}')
return v
class Config:
env_file = '.env'
settings = Settings()
For complete Pydantic configuration examples, see references/api-reference.md.