Summary: nuxt-website is one codebase that produces two completely separate Docker images, one per brand, via the THEME=7mind or THEME=7sleep build-time environment variable. Unlike the backend’s request-time dual-brand-routing, the frontend bakes the brand in at build time and deploys two distinct containers.
Sources: direct code inspection (Dockerfile, nuxt.config.ts, theme-helpers.js, themes.json, .github/workflows/_build-and-deploy.yml, .github/workflows/deploy-from-merge-legacy.yml)
Last updated: 2026-05-15
Why build-time, not request-time
The Nuxt website cannot do what the elixir-backend does (one binary, two brands chosen per request). The reasons are concrete:
- SCSS variables, design tokens, and Google Fonts differ between brands. Sass and style-dictionary resolve these at build time.
- Locale lists differ massively: 7mind builds nine locales (de, fr, nl, en, it, es, uk, us, ca) on different TLDs; 7sleep builds only
de. nuxt-i18n bakes this into the route table. - Auth is enabled for 7mind only.
auth: falseon 7sleep changes the generated routes. - Sitemap shape, recaptcha keys, Sentry DSN, favicons, even the cookie banner copy are all brand-specific and resolved during build.
So the answer is two separate builds. The brand decision is made once, in the Docker build args, and burned into the artifact.
How the multiplexing works
DockerfileacceptsARG THEMEand setsENV THEME=$THEME.- CI passes
THEME=7mind(or7sleep) as a build arg. The current new pipeline (_build-and-deploy.yml) only buildsTHEME=7mind. The legacy pipeline (deploy-from-merge-legacy.yml) builds both as separate parallel jobs producing two images:web-v2andweb-sleep. nuxt.config.tsreadsprocess.env.THEMEat config-load time and branches every brand-sensitive setting from there.theme-helpers.js+themes.jsonmap a theme name to its SCSS variables path (assets/scss/7mindvsassets/scss/7sleep).- The webpack
extendhook innuxt.config.tsregisters a~brandVariablesalias and a SCSS rule chain that usesnull-loaderfor files containing other-theme queries — so other-brand SCSS is dropped during compile. - Design tokens live under
tokens/{7mind,7sleep}/and are compiled into Vue-accessible JS at build time bymodules/design-tokens.js. - Brand-specific components live under
components/7sleep/or are gated via<template>conditionals on$config.theme.
Which brand goes where
| Image | Theme | Deploy target | Pipeline |
|---|---|---|---|
web-v2 (new) | 7mind | GKE application-cluster via Terraform, namespaces staging / production | _build-and-deploy.yml |
web-v2 (legacy) | 7mind | Old GKE cluster via Helm | deploy-from-merge-legacy.yml |
web-sleep (legacy) | 7sleep | Old GKE cluster via Helm | deploy-from-merge-legacy.yml |
The new Terraform pipeline does not currently build a 7sleep image. As of the latest workflow files, THEME=7mind is hardcoded. The 7sleep production frontend is still served from the legacy pipeline. Migrating 7sleep onto the new infra requires either a second Terraform module instance with its own image and ingress or a build matrix in _build-and-deploy.yml.
What agents should know
- Never hardcode brand in templates. Always use
$config.theme === '7mind'(or readprocess.env.THEMEat build time) and branch accordingly. process.env.THEMEis set at build time, not runtime. Changing it in K8s ConfigMap after the build does nothing; the SCSS, locales, and tokens are already compiled.- Adding a brand-specific feature means it can be present in one bundle and absent from the other, not toggleable at runtime. Plan accordingly.
- The new Terraform pipeline is 7mind-only. Don’t assume
/deploy productionships 7sleep changes; it does not. 7sleep deploys come from the legacydeploy-from-merge-legacy.yml. - Sentry projects, GTM containers, Chargebee namespaces, Braze keys, and reCAPTCHA keys all come in pairs keyed on
THEME. When adding integrations, add both unless you have a documented reason to only support one brand. - SCSS that uses other-brand variables fails the build because of the
~brandVariablesalias resolution. If you need to share SCSS, put it in shared paths that don’t reference theme-specific tokens. - The legacy pipeline still uses Helm under
k8s/base/{web-v2,web-sleep}/and pushes images toeu.gcr.io/mind-f62c0. The new pipeline uses Terraform underterraform/web-v2/and pushes toeurope-west3-docker.pkg.dev/sevenmind-infrastructure/application-cluster-repo/web-v2. Both register routes to the same public domains; do not assume only one ingress exists in front ofwww.7mind.de.
Related
- nuxt-website — the only repo with this build-time multiplexing pattern
- dual-brand-routing — the backend’s runtime equivalent (one binary, two brands)
- multi-domain-hostname-rewriting — orthogonal axis: a single brand build still adapts to multiple host families at runtime
- chargebee-billing — billing keys are one of many things that come in
7MIND_*/7SLEEP_*pairs