SSR Environment Variables
This guide explains SSR-related environment variables in Zova within the Cabloy monorepo.
Why SSR env configuration matters
SSR behavior often depends on environment variables that do not matter in exactly the same way for purely client-side execution.
Zova exposes SSR-related environment variables so the framework can configure key behaviors directly.
Representative configurable variables
Representative variables include:
SSR_PROFILESSR_COOKIE_THEMEDARK_DEFAULTSSR_API_BASE_URLSSR_PROD_PORT
These affect SSR profile selection, theme defaults, server-side API targeting, and SSR production port behavior. Response-cache defaults are resolved from the selected request-local profile; body-ready behavior is an opt-in of the selected layout module, not an environment or profile switch.
SSR profile
SSR_PROFILE is the standalone-flavor default for request-local SSR behavior:
public: the server renders without request-cookie credentials or cookie-backed theme resolution. Output must be anonymous-safe and may use public response caching.session: the server may recover request-cookie session state for normal route admission and authorized rendering. The response is alwaysCache-Control: private, no-store.
For Vona-backed SSR, SSR_PROFILE supplies the flavor default. After the frontend route is resolved, route.meta.ssrProfile can override that default before serverEntry runs. The resolved profile controls request-cookie capability and related SSR behavior; locale-aware URL handling remains the existing route.meta.locale contract. A profile never grants authentication, site admission, or API authorization; requiresAuth and Vona guards remain responsible for those decisions.
Route authors should choose the profile from the rendering contract rather than from the presence or absence of a locale parameter. Use session when SSR genuinely needs cookie-backed state, protected admission, personalized first paint, or private data; use public for an explicit URL-locale or deliberately locale-neutral, cache-safe, hydration-equivalent public contract. This is not an authentication requirement: an anonymous route should set requiresAuth: false, and session still does not grant Passport, Site, role, or API authority.
The selected layout owns sidebar restoration. A layout that enables layout.sidebar.bodyReadyObserver queues a request-local hidden-body metadata entry during SSR, registers its readiness condition and restoration callback, and then injects the generic browser observer. The observer restores browser-local sidebar state after the relevant layout DOM exists and reveals the body before hydration. Admin enables this path; Web and Empty disable it. Therefore, a Web route using ssrProfile: 'session' remains private, no-store without gaining the Admin sidebar observer.
The selected layout also supplies its own desktop sidebar fallback and responsive breakpoint: the Admin layout defaults to open and the Web layout defaults to closed, and both currently use 1023px as their independently configured breakpoint. Browser-local sidebar preference can override that fallback. The selected layout passes its breakpoint to the SSR browser handoff; it is not profile-specific. SSR profile selection does not change a layout's sidebar behavior.
SSR response cache control
After Zova resolves the route profile, a session response immediately receives Cache-Control: private, no-store, before router guards or rendering can terminate it. A successfully rendered public route receives a response-cache header according to the route's locale metadata and any explicit meta.ssrProfileOptions.responseCache policy.
For a public route, the default policy is:
meta.locale: true: use the configured public profile cache policy;- missing or false
meta.locale: useexpires: 0, which emitsCache-Control: no-cache, no-store, must-revalidate.
The second case prevents a CDN from sharing HTML whose hydration-time locale may still come from a browser cookie while the URL does not identify the locale. A route-level meta.ssrProfileOptions.responseCache override remains authoritative, including false; use an explicit override only when the route's complete SSR HTML is safe to share for that URL.
Cabloy Basic uses different flavor defaults:
| Flavor | Default profile | SSR response header |
|---|---|---|
| Web | public | locale-aware routes use public, max-age=600 |
| Admin | session | private, no-store |
A route can override the flavor profile through meta.ssrProfile and can define a public response-cache policy through meta.ssrProfileOptions.responseCache. For Cloudflare cache-rule alignment that preserves these origin headers, see Docker + Cloudflare Deployment.
Theme implications of SSR_PROFILE
SSR_PROFILE determines whether the server can use cookie-backed theme state for the current request.
session: the server can resolve theme state from request cookies during SSR.public: server theme reads are not authoritative for the browser's final theme. Keep theme-sensitive rendering hydration-tolerant and use the established browser-finalization path.
Use the active edition and UI library to determine the adapter-level implementation. Cabloy Basic and Cabloy Start share the profile contract but do not necessarily use the same SSR theme handoff.
For the broader theme usage contract and edition-aware checklist, see Theme Guide. For the runtime/flavor selection model behind these env choices, see Environment and Config Guide.
Dynamic environment variables
The runtime also exposes environment variables that describe the current execution context, such as:
SSRDEVPRODCLIENTSERVER
These are important because SSR-aware code often needs to distinguish:
- server versus client behavior
- development versus production behavior
- SSR mode versus non-SSR mode
Implementation checks for SSR environment-sensitive changes
When editing SSR-sensitive code, do not assume one execution environment.
It should explicitly consider whether the code path depends on:
- server versus client execution
- dev versus prod behavior
- SSR-specific environment configuration
That is often the difference between code that “works locally once” and code that fits the actual Zova SSR model.
For the broader mode/appMode/flavor and env/config loading model, see Environment and Config Guide.