env-config by aiskillstore
Use when setting up environment configuration, loading .env files, or managingapplication settings across environments.Triggers for: .env setup, loading environment variables, Pydantic BaseSettings,configuration validation, or secret management.NOT for: code-specific logic, feature flags, or runtime feature toggles.
Content & Writing
85 Stars
2 Forks
Updated Jan 19, 2026, 04:39 AM
Why Use This
This skill provides specialized capabilities for aiskillstore's codebase.
Use Cases
- Developing new features in the aiskillstore repository
- Refactoring existing code to follow aiskillstore standards
- Understanding and working with aiskillstore's codebase structure
Install Guide
2 steps- 1
Skip this step if Ananke is already installed.
- 2
Skill Snapshot
Auto scan of skill assets. Informational only.
Valid SKILL.md
Checks against SKILL.md specification
Source & Community
Skill Stats
SKILL.md 368 Lines
Total Files 1
Total Size 0 B
License NOASSERTION
---
name: env-config
description: |
Use when setting up environment configuration, loading .env files, or managing
application settings across environments.
Triggers for: .env setup, loading environment variables, Pydantic BaseSettings,
configuration validation, or secret management.
NOT for: code-specific logic, feature flags, or runtime feature toggles.
---
# Environment Configuration Skill
Expert environment configuration management for Python/FastAPI projects with secure secrets handling and multi-environment support.
## Quick Reference
| Pattern | Usage |
|---------|-------|
| Load .env | `load_dotenv()` at application start |
| Access var | `settings.DB_URL`, `settings.JWT_SECRET` |
| Required var | `Field(..., description="Database URL")` |
| Optional var | `DB_HOST: str = "localhost"` |
| Secret type | `SecretStr` for sensitive values |
## Project Structure
```
project/
├── .env # Local development (NOT committed)
├── .env.example # Template with all required vars (committed)
├── .env.staging # Staging environment
├── .env.production # Production environment (managed by infra)
└── config/
├── __init__.py
└── settings.py # Pydantic BaseSettings
```
## settings.py - Base Configuration
```python
# config/settings.py
from functools import lru_cache
from pydantic import Field, SecretStr
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore",
)
# Application
APP_NAME: str = "ERP System"
DEBUG: bool = False
API_V1_PREFIX: str = "/v1"
# Database
DB_URL: str = Field(
...,
description="PostgreSQL connection URL",
examples=["postgresql://user:pass@localhost:5432/dbname"],
)
DB_POOL_SIZE: int = Field(default=5, ge=1, le=100)
# JWT Authentication
JWT_SECRET_KEY: SecretStr = Field(
...,
description="Secret key for JWT signing",
)
JWT_ALGORITHM: str = "HS256"
JWT_EXPIRATION_MINUTES: int = Field(default=15, ge=1)
# Redis (Optional)
REDIS_URL: str | None = None
# Logging
LOG_LEVEL: str = Field(default="INFO", pattern="^(DEBUG|INFO|WARNING|ERROR)$")
# CORS
CORS_ORIGINS: list[str] = ["http://localhost:3000"]
@property
def is_production(self) -> bool:
return not self.DEBUG
@lru_cache
def get_settings() -> Settings:
"""Cached settings instance for application lifecycle."""
return Settings()
```
## .env.example - Template File
```bash
# .env.example - Copy to .env and fill in values
# DO NOT commit actual secrets!
# Application
APP_NAME="ERP System"
DEBUG=false
API_V1_PREFIX="/v1"
# Database (required)
DB_URL="postgresql://user:password@localhost:5432/erp_db"
# JWT Authentication (required - generate with: openssl rand -hex 32)
JWT_SECRET_KEY="your-secret-key-here-generate-with-openssl-rand-hex-32"
JWT_ALGORITHM="HS256"
JWT_EXPIRATION_MINUTES=15
# Redis (optional)
# REDIS_URL="redis://localhost:6379/0"
# Logging
LOG_LEVEL="INFO"
# CORS
CORS_ORIGINS="http://localhost:3000"
```
## .env - Local Development
```bash
# .env - Local development only
# NEVER commit this file to version control
APP_NAME="ERP System"
DEBUG=true
API_V1_PREFIX="/v1"
# Local PostgreSQL
DB_URL="postgresql://postgres:postgres@localhost:5432/erp_dev"
# Generate with: openssl rand -hex 32
JWT_SECRET_KEY="local-dev-secret-key-change-in-production"
JWT_ALGORITHM="HS256"
JWT_EXPIRATION_MINUTES=15
# Local Redis (if using)
REDIS_URL="redis://localhost:6379/0"
LOG_LEVEL="DEBUG"
CORS_ORIGINS="http://localhost:3000,http://localhost:5173"
```
## Usage in Application
### FastAPI Application
```python
# main.py
from contextlib import asynccontextmanager
from dotenv import load_dotenv
load_dotenv() # Load .env file
from config.settings import get_settings
@asynccontextmanager
async def lifespan(app):
settings = get_settings()
print(f"Starting {settings.APP_NAME} in {'DEBUG' if settings.DEBUG else 'PROD'} mode")
yield
print("Shutting down...")
app = FastAPI(
title=get_settings().APP_NAME,
lifespan=lifespan,
)
# Include routers
from app.routers import fees, students
app.include_router(fees.router, prefix=get_settings().API_V1_PREFIX)
app.include_router(students.router, prefix=get_settings().API_V1_PREFIX)
```
### Database Connection
```python
# database.py
from sqlmodel import create_engine, Session
from config.settings import get_settings
settings = get_settings()
engine = create_engine(
settings.DB_URL.get_secret_value() if hasattr(settings.DB_URL, 'get_secret_value') else settings.DB_URL,
pool_size=settings.DB_POOL_SIZE,
max_overflow=10,
)
def get_session():
with Session(engine) as session:
yield session
```
### JWT Configuration
```python
# auth/jwt.py
from datetime import timedelta
from config.settings import get_settings
settings = get_settings()
JWT_SECRET = settings.JWT_SECRET_KEY.get_secret_value()
JWT_ALGORITHM = settings.JWT_ALGORITHM
ACCESS_TOKEN_EXPIRE_MINUTES = settings.JWT_EXPIRATION_MINUTES
def create_access_token(data: dict, expires_delta: timedelta | None = None) -> str:
# ... token creation logic
pass
```
## Multi-Environment Support
### Environment-Specific Configs
```python
# config/settings.py
class Settings(BaseSettings):
# ... shared settings
@classmethod
def from_env(cls, env: str = "development") -> "Settings":
"""Load settings for specific environment."""
env_file = {
"development": ".env",
"staging": ".env.staging",
"production": ".env.production",
}.get(env, ".env")
return cls(_env_file=env_file)
```
### Production Override
```bash
# Production should use environment variables, not .env files
# Set these in your deployment platform (Docker, K8s, Cloud Run, etc.)
export DB_URL="postgresql://prod_user:[email protected]:5432/erp_prod"
export JWT_SECRET_KEY="production-secret-key-from-secrets-manager"
export DEBUG=false
export LOG_LEVEL="WARNING"
```
## Secret Management
### Generate Secrets
```bash
# Generate secure random secret
openssl rand -hex 32 # For JWT_SECRET_KEY
# Generate database password
openssl rand -base64 32
```
### Secret Rotation Script
```python
# scripts/rotate_secret.py
"""Rotate a secret in all environments."""
import os
import re
def rotate_secret(env_file: str, key: str, new_value: str):
"""Replace secret value in .env file."""
with open(env_file, "r") as f:
content = f.read()
# Pattern to match KEY=value
pattern = f"^{key}=.*$"
replacement = f"{key}={new_value}"
new_content = re.sub(pattern, replacement, content, flags=re.MULTILINE)
with open(env_file, "w") as f:
f.write(new_content)
print(f"Rotated {key} in {env_file}")
if __name__ == "__main__":
import sys
if len(sys.argv) != 4:
print("Usage: rotate_secret.py <env_file> <key> <new_value>")
sys.exit(1)
rotate_secret(sys.argv[1], sys.argv[2], sys.argv[3])
```
## Quality Checklist
- [ ] **Validation on load**: All required fields have `Field(..., ...)` validation
- [ ] **No leaks in logs**: Use `SecretStr` for sensitive values, never print settings
- [ ] **.env.example committed**: Template shows all required variables
- [ ] **.env.gitignored**: Local development file excluded from version control
- [ ] **Secrets generated**: JWT secrets use `openssl rand -hex 32`
- [ ] **Environment isolation**: Different configs for dev/staging/production
- [ ] **Type safety**: All settings have proper type annotations
## Integration with Other Skills
| Skill | Integration Point |
|-------|-------------------|
| `@jwt-auth` | JWT_SECRET_KEY from settings |
| `@sqlmodel-crud` | DB_URL from settings |
| `@fastapi-app` | All app settings from settings |
| `@db-migration` | Database URL for migrations |
| `@api-route-design` | API prefix, CORS origins |
## Security Best Practices
### DO
- Use `SecretStr` for passwords, API keys, tokens
- Rotate secrets regularly
- Use different secrets per environment
- Store production secrets in secrets manager
- Validate all required settings at startup
### DON'T
- Never commit `.env` files to version control
- Never hardcode secrets in source code
- Never log settings or environment variables
- Never use default/placeholder secrets in production
- Never expose configuration details in error messages
## Startup Validation
```python
# config/validate.py
"""Validate required configuration at startup."""
from pydantic import ValidationError
from config.settings import Settings
def validate_settings() -> bool:
"""Ensure all required settings are configured."""
try:
settings = Settings()
return True
except ValidationError as e:
print("Configuration validation failed:")
for error in e.errors():
print(f" - {error['loc'][0]}: {error['msg']}")
return False
if __name__ == "__main__":
if not validate_settings():
exit(1)
```
Name Size