Overview
Open Wearables publishes two production images to Docker Hub:
The single backend image runs the API, worker, beat, and flower — the command is supplied by your orchestrator (
scripts/start/app.sh, worker.sh, beat.sh, flower.sh), exactly as in docker-compose.yml.
Configuring the frontend API URL at runtime
What changed: the frontend used to bake
VITE_API_URL into the JavaScript bundle at build time, which meant a prebuilt image could only ever talk to one backend. The API URL is now resolved at runtime, so the same published image works against any backend without rebuilding.VITE_API_URL as an environment variable on the frontend container. The Nitro server reads it at startup and injects it into the served HTML before the app loads:
VITE_API_URL is not set, it falls back to http://localhost:8000.
VITE_API_URL is a single variable used for both build-time (Vite inlines import.meta.env) and runtime configuration. When the same variable is set both in an .env file and via the container’s environment:, the container environment wins — so runtime always overrides any baked-in value.How it works
Because the frontend is server-rendered (TanStack Start on Nitro), the value travels from the container env to the browser like this:- The Nitro server reads
process.env.VITE_API_URLat request time. - It injects
window.__APP_CONFIG__ = { apiUrl: "..." }into the HTML<head>before the app hydrates. - The API client reads that value. (Resolution order: injected runtime value →
VITE_API_URLbaked at build →http://localhost:8000.)
frontend/src/lib/api/runtime-config.ts.
Example: deploying one client
For a client served atclient1.com with its API at api.client1.com:
config/.env), so its image needs no per-client rebuild either.
Related Guides
- Deploy to Railway - One-click managed deployment
- Raw Payloads Storage - Backend runtime configuration example

