We use analytics to understand how our website is used. No personal data is collected.

October 20, 2025 · Piyush Ranjan Mishra

Building a White-Label Website Generator: Templating and Multi-Tenant Frontend Architecture

FrontendArchitectureMulti-TenantR Systems

At R Systems, part of leading the dotstudioPro client engagement involved building white-label website generation tooling for their partner network, and reducing white-label website creation time by 10% through tooling improvements. “White-label” here meant each partner got a themed, branded site built from a shared underlying platform — the engineering problem was making new partner sites fast and low-risk to produce, without every partner’s site becoming its own diverging codebase.

The trap: one codebase per partner

The path of least resistance when a new partner needs a website is to fork the existing one and customize it. This is fast for the first partner, and it’s a maintenance disaster by the fifth — every bug fix and feature now needs to be manually ported across N diverging copies, and inevitably some copies fall behind. The alternative, which is more work upfront and pays for itself quickly at any real scale, is a single shared codebase parameterized by configuration — theme, content, branding — rather than forked per partner.

Theming as data, not as code branches

Partner-specific customization (colors, logos, fonts, layout variants) lived entirely in configuration consumed by the shared component tree, not in conditional code branches scattered through components. A component checking if (partner === "acme") { ... } anywhere in the codebase was treated as a bug waiting to happen — it meant that partner’s customization only existed inside a specific engineer’s memory of where that conditional lived, and every new partner needing similar treatment meant another conditional, compounding indefinitely.

interface PartnerTheme {
  colors: { primary: string; secondary: string; accent: string };
  logo: { src: string; alt: string };
  layout: "standard" | "compact" | "media-forward";
  content: PartnerContent;
}

Every partner site rendered from the same components, driven entirely by a PartnerTheme object — a genuinely new partner most of the time meant assembling a new theme configuration, not writing new component code.

Where genuine per-partner code was still necessary

Not every customization request fit cleanly into theme configuration — occasionally a partner needed a layout variant or a feature that didn’t exist yet. The discipline that kept the system from decaying back into per-partner forks: a new layout variant or feature became a new, named option in the shared system (available to any partner who wanted it), not a one-off branch for a single partner. This meant occasionally pushing back on a request to build something genuinely one-off, in favor of building it as a reusable option — slower for that specific request, but it’s what kept the system from re-accumulating the same maintenance burden it was built to avoid.

The 10% time reduction came from tooling, not just architecture

The architectural decision (shared codebase, config-driven theming) made a faster generation process possible, but the actual time savings came from tooling built on top of it — a CLI/scaffolding tool that took a partner’s brand assets and generated a starting theme configuration automatically, rather than someone manually writing the configuration by hand for every new partner. Reducing “spin up a new partner site” from a multi-step manual process to running a scaffolding tool and reviewing/adjusting the generated output was where the measured time reduction actually came from — the architecture made this tooling possible to build cheaply; the tooling is what delivered the number. A companion React Native plugin, built on the same shared-core principle, took roughly another 15% off the time to onboard a new partner onto the mobile side.

Testing across partner variants without multiplying test suites

This connects directly to the E2E testing work on the same client engagement — core flows were tested against structural assertions that held across all partner themes, with a smaller layer of partner-specific visual checks, rather than a fully separate test suite per partner. The same “shared core, thin partner-specific layer” principle that made the frontend maintainable also kept testing maintainable, for the same underlying reason: anything that scales linearly with partner count becomes a bottleneck eventually, and it’s worth designing against that from the start rather than discovering it once the partner count has already grown past comfortable.

The actual lesson

White-label systems fail the same way most multi-tenant systems fail — not through any single bad decision, but through the accumulation of “just this once” per-tenant special cases that each seemed reasonable in isolation. The discipline that kept this system maintainable was treating every customization request as a design question (does this belong in configuration, or does it need to become a reusable option in the shared system) rather than defaulting to the fastest path for the immediate request.