Skip to content

Environment Configuration

How environment variables are declared, validated, and wired through to deployments. Read this before adding or changing any env var.

The Settings model is the single source of truth

Every environment variable is declared once as a typed field on the Settings model in campus_core/settings_envs.py (pydantic-settings) - the single source of truth. settings.py instantiates config = Settings() and sources its Django globals from it; validation (and fail-fast on missing required vars) happens at import. To add or change an env var, edit the Settings model, then read it as config.<NAME> in settings.py - don't reintroduce ad-hoc os.environ/env(...) reads.

Required vs optional vs cloud-required

A field's requirement is its default: no default = required everywhere; a default = optional. For a var that has a safe local default but must be set in the cloud (e.g. REDIS_URL, or RATE_LIMIT_TRUSTED_PROXY_HOPS - the rate limiter's trusted X-Forwarded-For suffix, 1 behind the ALB and 0 locally), tag it cloud_required=True via the deploy(...) metadata so it's enforced at cloud boot and in the deploy-contract check.

The deploy-contract check

scripts/check_deploy_contract.py (run by gate.sh, pre-commit, and CI) reconciles the model against the ECS task definition (infrastructure/app/ Terraform), .env_sample, and EventBridge schedules - so adding a var without wiring the pipeline fails the PR.

Where values live

The .env file lives in campuscore_app/. Docker Compose overrides DB vars via environment directives; cloud deployments use AWS Secrets Manager. See .env_sample for required variables.

Terraform-only knobs are a different chain

Not every per-environment value is a Settings field. Infrastructure knobs the container never reads (database sizing, the read replica, schedule crons) are GitHub Environment variables that deploy-aws.yml passes to Terraform as TF_VAR_* values - the GitHub Environment Variables Reference is their registry, and RDS Configuration documents the database ones.