Backend URL Configuration#
The frontend resolves API endpoint URLs at runtime rather than bake them in at build time. This lets the same Docker image target different backends without a rebuild.
How it works#
The resolution chain has three layers:
-
window.__env(runtime injection) — At container startup,entrypoint.shgeneratespublic/__env.js, a plain JavaScript file that assigns awindow.__envobject. The key variable isNEXT_PUBLIC_AGENTA_API_URL, whose value is resolved from shell variables in priority order:$AGENTA_API_URL→$DOMAIN_NAME+ optional$AGENTA_PORT→http://localhost. -
getEnvhelper —dynamicEnv.tsexportsgetEnv(envKey). In a browser context it preferswindow.__env[envKey]if the object is present and non-empty; otherwise it falls back toprocess.env(compile-time) . -
getAgentaApiUrl—utils.tscallsgetEnv("NEXT_PUBLIC_AGENTA_API_URL"). If that returns empty (e.g., local dev without a.envfile), it falls back towindow.location.protocol + "//" + window.location.hostname— i.e., same-origin .
The __env.js script is loaded with strategy="beforeInteractive" in GlobalScripts.tsx, so window.__env is populated before React hydration runs .
Flow diagram#
Container startup
└── entrypoint.sh → writes public/__env.js
└── window.__env = { NEXT_PUBLIC_AGENTA_API_URL: "...", ... }
Browser load
└── <Script src="/__env.js" strategy="beforeInteractive" />
└── window.__env available before hydration
API call
└── axiosConfig.ts → getAgentaApiUrl()
└── getEnv("NEXT_PUBLIC_AGENTA_API_URL")
├── window.__env[key] (runtime, preferred)
├── process.env[key] (build-time fallback)
└── window.location.origin (same-origin last resort)
Key files#
| File | Role |
|---|---|
web/entrypoint.sh | Generates __env.js at container start; maps shell env vars to window.__env |
src/lib/helpers/dynamicEnv.ts | getEnv() — unified accessor; prefers window.__env over process.env |
src/lib/helpers/utils.ts | getAgentaApiUrl() — resolves the base API URL with same-origin fallback |
src/lib/api/assets/axiosConfig.ts | Creates the axios instance using getAgentaApiUrl() as baseURL |
src/components/Scripts/GlobalScripts.tsx | Loads /__env.js before interactive to make window.__env available at hydration |
Environment variables#
All variables live under the NEXT_PUBLIC_ prefix so Next.js includes them in client bundles, but the window.__env path bypasses the build entirely — making post-build overrides possible in Docker .
| Shell variable (Docker) | window.__env / process.env key | Default |
|---|---|---|
AGENTA_API_URL | NEXT_PUBLIC_AGENTA_API_URL | $DOMAIN_NAME/api or http://localhost/api |
AGENTA_WEB_URL / WEBSITE_DOMAIN_NAME | NEXT_PUBLIC_AGENTA_WEB_URL | $DOMAIN_NAME or http://localhost |
AGENTA_LICENSE | NEXT_PUBLIC_AGENTA_LICENSE | oss |
Notes for engineers#
- Local dev: Set
NEXT_PUBLIC_AGENTA_API_URLin.env.local. Without it, the app falls back to same-origin, which works when the API is proxied through the Next.js dev server. - Docker: Set
AGENTA_API_URL(orDOMAIN_NAME) as container environment variables — do not rely onNEXT_PUBLIC_*build args. ngrok/ tunnels: The axios interceptor sets thengrok-skip-browser-warningheader when the request URL does not already contain the configured API URL .- Demo / cloud mode:
GlobalScripts.tsxloadsCloudScriptsinstead and skips__env.jsinjection , meaning the demo variant uses a different env injection path.