Every configuration surface in Transit, by app, with variable names and where each value comes from. No values for secrets appear here.
| Reference | Value |
|---|---|
| Subject and boundary | Environment variable names, Worker bindings and public variables. Secret values live only in GitHub Actions secrets, Cloudflare and the VM's runtime environment. |
| Verified source | settings.py, .env.example, docker-compose.yml, web wrangler.toml, proxy wrangler.toml, core/models.py at main 9733eb26d92533f56cdc8bc46b81b93fbb5987c8, checked November 10, 2026. |
| Support state | Implemented. Settings and .env.example are the executable contract for the pipeline; change them together. |
apps/db)| Group | Variables | Notes |
|---|---|---|
| Runtime | APP_ENV, LOG_LEVEL, PROVIDER_TIMEZONE, PIPELINE_PAUSED |
Timezone defaults to America/Toronto |
| Database | DATABASE_URL |
Compose builds it from POSTGRES_* and TRANSIT_APP_DB_USER; the password stays in libpq PGPASSWORD |
| STM feeds | STM_PROVIDER_ID, STM_API_KEY, STM_STATIC_GTFS_URL, STM_GIS_URL, STM_RT_TRIP_UPDATES_URL, STM_RT_VEHICLE_POSITIONS_URL, STM_I3_ALERTS_URL |
Secret: STM_API_KEY |
| OC Transpo feeds | OCTRANSPO_API_KEY, OCTRANSPO_STATIC_GTFS_URL, OCTRANSPO_RT_TRIP_UPDATES_URL, OCTRANSPO_RT_VEHICLE_POSITIONS_URL |
Named by octranspo.yaml; secret: OCTRANSPO_API_KEY |
| Bronze storage | BRONZE_STORAGE_BACKEND (local or s3), BRONZE_LOCAL_ROOT, BRONZE_S3_ENDPOINT, BRONZE_S3_BUCKET, BRONZE_S3_ACCESS_KEY, BRONZE_S3_SECRET_KEY, BRONZE_S3_REGION |
Local by default; secrets: access and secret keys |
| Snapshots | SNAPSHOT_STORAGE_BACKEND, SNAPSHOT_LOCAL_ROOT, SNAPSHOT_R2_BUCKET, SNAPSHOT_PUBLIC_BASE_URL, SNAPSHOT_BASEMAP_STYLE_URL, SNAPSHOT_BASEMAP_ATTRIBUTION, SNAPSHOT_PUBLISH_CONCURRENCY |
Local by default; concurrency 16, values of 1 or less upload serially |
| Realtime and pruning | REALTIME_POLL_SECONDS (30), REALTIME_STARTUP_DELAY_SECONDS (0), REALTIME_WATCHDOG_SECONDS (600), REALTIME_SHUTDOWN_GRACE_SECONDS (150, must be under 180), PRUNER_SLEEP_SECONDS (15), SILVER_REALTIME_PRUNE_BATCH, GOLD_FACT_PRUNE_BATCH, GOLD_REALTIME_ANALYZE_MIN_INTERVAL_SECONDS, GOLD_REPORTING_OPEN_WINDOW_DAYS |
REALTIME_POLL_SECONDS is the base of the worker tick; phased feeds can shorten it. The watchdog and shutdown-grace settings have defaults in Settings and are not listed in .env.example |
| Retention | STATIC_DATASET_RETENTION_COUNT, SILVER_REALTIME_RETENTION_DAYS, SILVER_I3_CLOSED_RETENTION_DAYS, GOLD_FACT_RETENTION_DAYS, GOLD_WARM_ROLLUP_RETENTION_DAYS, BRONZE_*_RETENTION_DAYS, BRONZE_PRUNE_MAX_OBJECTS_PER_BATCH, BRONZE_PRUNE_MAX_BATCHES |
Defaults on ‣ |
| Backups | BACKUP_S3_PREFIX, BACKUP_RETENTION_COUNT, BACKUP_EXCLUDE_TABLE_DATA, BACKUP_COMPRESSION |
Written to the Bronze bucket |
| Health | HEALTH_DATABASE_TIMEOUT_SECONDS, HEALTH_FEED_TIMEOUT_SECONDS, HEALTH_MAX_PIPELINE_AGE_SECONDS, HEALTH_RUNTIME_CACHE_SECONDS |
Health service only |
| Validation | STRICT_GTFS |
Fallback when a manifest omits strict_gtfs |
| Tests | TRANSIT_TEST_DATABASE_URL, TRANSIT_TEST_DATABASE_DISPOSABLE |
See ‣ |
Compose gives each service only the variables it needs: the pruner and health service receive no feed keys.
Per-provider behavior is set in apps/db/config/providers/*.yaml, validated by core/models.py, not by environment variables. Values per provider are on Providers.
| Key | Default | Purpose |
|---|---|---|
feeds.<endpoint>.refresh_interval_seconds |
Required | Capture interval for that endpoint |
feeds.<endpoint>.refresh_phase_seconds |
None | Optional offset from the UTC epoch that aligns captures to the source's rebuilds |
provider.live_source_lag_seconds |
0 | Declared age of the source's live data at capture; published as source_lag_s |
provider.max_vehicle_speed_kmh |
130 (raised from 100 in #742) | Silver nulls reported speeds above this cap |
realtime.lines_without_live_data |
Empty | Lines declared without live data, selected by route_ids or route_types under a gap_id |
public.basemap_bounds |
None | Area of the provider's basemap extract |
POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_BIND_ADDRESS (default 127.0.0.1), POSTGRES_HOST_PORT, CADDY_SITE_ADDRESS, CADDY_BIND_ADDRESS (default 127.0.0.1), CADDY_HTTP_PORT, CADDY_HTTPS_PORT. A non-loopback bind is a deliberate exposure change.
apps/web)| Kind | Name | Value or purpose |
|---|---|---|
| Public variable | PUBLIC_SITE_ORIGIN |
https://transit.yesid.dev |
| Public variable | PUBLIC_V1_BASE |
https://data.yesid.dev/v1, the browser snapshot origin |
| Public variable | PUBLIC_V1_PROVIDER |
Default provider when the URL has no provider query |
| Public variable | PUBLIC_INDEXING |
true in production, false for previews |
| Public variable | PUBLIC_PROVIDER_SHORT_NAME, PUBLIC_PROVIDER_CITY |
STM, Montréal: default identity before the provider catalog loads |
| Public variable | PUBLIC_SITE_AUTHOR, PUBLIC_TWITTER_SITE, PUBLIC_TWITTER_CREATOR |
Metadata |
| Public variable | PUBLIC_PLAUSIBLE_DOMAIN, PUBLIC_VITALS_ENABLED |
Analytics and vitals; unset means nothing is sent |
| Binding | ASSETS |
Static assets in .svelte-kit/cloudflare |
| Binding | SNAPSHOTS |
R2 bucket transit-snapshots for server-side reads |
| Binding | DATA |
Service binding to transit-data-proxy |
| Runtime metadata | TRANSIT_COMMIT_SHA, TRANSIT_BRANCH |
Injected by verification/deployment tooling, returned by web /health |
| Public variable | PUBLIC_CF_BEACON_TOKEN |
Enables the Cloudflare Web Analytics beacon when supplied |
| Optional binding | WEB_VITALS |
Analytics Engine dataset for /api/vitals; absent means beacons are accepted and dropped |
apps/data-proxy)One binding, SNAPSHOTS (R2 transit-snapshots), and two routes: transit.yesid.dev/data/* and transit.yesid.dev/api/v1/*. No secrets.
Workflows read DATABASE_URL, Bronze keys, SNAPSHOT_R2_BUCKET and SNAPSHOT_PUBLIC_BASE_URL from GitHub Actions secrets; the preview and deploy jobs also use Cloudflare credentials held by GitHub. Contributors never need any of them, and fork pull requests run the checks without them.
| Storage | Key or preference | Contract |
|---|---|---|
| localStorage | sections-choice |
Bulk action writes expanded or collapsed across pages and visits; a first visit does not write a choice. Individual toggles affect only the current view |
| localStorage | Theme, motion (transit:motion-mode: raw by default or smooth), map panels and panel width |
Separate UI preferences; independent tools and map layout are outside the section bulk action |
| sessionStorage | Navigation scroll positions | Browser-session navigation state |
On pages with at least two eligible content sections and the bulk control, first-visit content (no stored choice, or a malformed one) starts expanded with the control neutral and labelled Collapse all. A stored collapsed collapses content across pages and visits. The TOC card starts open. LocalStorage persistence lasts until the preference changes or site data is cleared; failed storage access is tolerated. legal.copy.ts owns the EN/FR device-storage disclosure; the released preference module (v0.40.0, adopted in #738) owns the key and values.