Fix environment variables missing at build time on Coolify
Error: Build-time error: process.env.NEXT_PUBLIC_* / VITE_* / API URL is undefined during build — values set in Coolify are empty in the built bundle (e.g. ReferenceError or fetch to "undefined")
Variables you set in Coolify exist at runtime but weren't injected during the image build, so anything baked in at build (NEXT_PUBLIC_*, VITE_*, REACT_APP_*) comes out empty.
Coolify scopes every variable independently for Build and Runtime, each with its own checkbox (both ON by default). If a variable's Build Variable checkbox is OFF, the value is not passed as a Docker --build-arg, so framework variables that are inlined into the bundle at build time (NEXT_PUBLIC_*, VITE_*, REACT_APP_*) compile to undefined even though they read fine at runtime. For Dockerfile build packs there is a second trap: Docker only exposes a --build-arg to a RUN step if a matching ARG is declared in the Dockerfile, so an undeclared build variable is silently dropped.
The fix
In Coolify open the app's Environment Variables in Normal view, find each variable the build needs, and make sure its Build Variable checkbox is ON. Save. (Both Build and Runtime are ON by default for new variables, but check existing ones.)
NEXT_PUBLIC_API_URL=https://api.your-domain.com # Build Variable = ONFor Dockerfile build packs, declare a matching ARG in the Dockerfile before you use it, then promote it to ENV so the build step can read it. Without the ARG line Docker drops the --build-arg value.
ARG NEXT_PUBLIC_API_URL ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL RUN npm run buildMulti-stage Dockerfile gotcha: an ARG declared before FROM goes out of scope after FROM. Re-declare the ARG inside the stage that runs the build, or the value will be empty there.
FROM node:20 AS build ARG NEXT_PUBLIC_API_URL ENV NEXT_PUBLIC_API_URL=$NEXT_PUBLIC_API_URL RUN npm run buildKeep secrets you only need at runtime (DB passwords, private API keys) with Build Variable OFF so they're not baked into the image layers. Only turn Build Variable ON for values the build genuinely inlines. For sensitive values you must use during build, enable Docker Build Secrets instead of a plain build arg.
Redeploy with a fresh build so the new build-args take effect. If values still look stale, trigger a redeploy with the build cache cleared (cached layers will reuse the old empty values).
Verify it worked
After a fresh redeploy the real value appears in the built output instead of "undefined" — check the served HTML for SSR/inlined values, or the JS chunks / network requests for client-bundle values. The build log should show the variable passed as a build arg.
curl -s https://your-domain.com | grep -o 'api.your-domain.com' || echo 'not in root HTML — also check JS chunks / network tab'Related Coolify errors
- www.domain.com cert error but apex works
- WebSocket connection to 'wss://<your-domain>:6001/app/...' failed (UI shows "WARNING: Cannot connect to real-time service")
- NET::ERR_CERT_AUTHORITY_INVALID
- TRAEFIK DEFAULT CERT / self-signed certificate