ADR-0006: Runtime Environment Variable Injection
Date: 2026-03-23
Status
Accepted
Context
The web app (webApp/) is built with Vite, which bakes import.meta.env.VITE_* variables into the JavaScript bundle at compile time. This is incompatible with containerised deployments where the same Docker image must run against different environments (dev, staging, production) with different API URLs and Keycloak configurations.
The main branch (Next.js) solved this with a public/env.js file containing window.__env__ with shell-style placeholder values ("${VARIABLE_NAME}"), loaded via a <script> tag in the HTML shell, and replaced at container startup using envsubst.
Decision
Adopt the same window.__env__ pattern for the webApp/ Vite SPA.
Implementation
1. webApp/public/env.js
A static file committed to the repo containing placeholder values:
2. webApp/index.html
Load the script before the React bundle:
3. webApp/src/config.ts
A typed config module that reads from window.__env__ with fallbacks:
All components and providers import from config.ts — never from import.meta.env directly.
4. Container entrypoint
At container startup, before serving the app, run:
This replaces ${KEYCLOAK_URL} etc. with the actual values from the container environment.
5. webApp/.env.example
Documents the expected environment variable names for operators:
Note: these are not VITE_ prefixed. They are passed to the container, not to the Vite build.
Consequences
The same Docker image runs unchanged across all environments; only the container environment variables differ.
import.meta.env.VITE_*is not used anywhere in the application code.Local development requires either running
envsubstmanually, or providing a pre-populatedwebApp/public/env.js(not committed with real values — addwebApp/public/env.jsto.gitignore, keeping only the template).The
envsubststep must be part of the containerENTRYPOINTor an init script.