2024

Building a Multi-Brand, Multi-Language Solution from a Single Monorepo

How I helped design and deliver the architecture behind BetKing and SuperSportBet at Kingmakers

At Kingmakers, I helped lead the architectural work required to scale a front-end application that originally served a single brand into a solution capable of supporting multiple brands and multiple languages, while maintaining one shared codebase inside a monorepo.

The brands involved were:

  • betking.com
  • supersportbet.com

The objective was clear:

Support multiple brands and multiple languages while keeping a single front-end codebase.

This article explains the approach I helped design, the architectural decisions we made, and how we safely rolled the solution out to production.

The Starting Point

When I joined the team working on this part of the solution, the setup was simple:

  • one front-end codebase
  • one brand
  • one consistent user experience

Because of this simplicity, development was fast and predictable.

However, the business required us to expand the solution so that:

  1. the same front-end would support multiple brands
  2. each brand could support multiple languages and locales
  3. we should avoid duplicating front-end applications

This meant we needed to evolve the architecture without compromising maintainability.

Aligning with Business Requirements

Before implementing a solution, I worked with stakeholders to understand:

  • which brands we needed to support
  • which countries and languages each brand would operate in

This early alignment allowed me and the team to design a solution that would scale properly instead of solving only the immediate requirement.

One of the most important conclusions from this discovery phase was:

Brand and language should not be solved using the same mechanism.

They have different operational risks and therefore required different approaches.

My Key Architectural Decision: Separate Brand and Locale

The architecture I helped introduce separated brand configuration from language configuration.

Brand

Brand needed to be strict and deterministic.

Serving the wrong branding would immediately damage user trust.

Locale

Locale needed to be dynamic and flexible, with safe fallbacks when content was unavailable.

This separation allowed us to build a solution that was both safe and scalable.

Implementing Multi-Brand Support

To support multiple brands from the same codebase, I helped introduce a theme-based architecture.

The idea was simple:

  • keep one front-end codebase
  • move all styling and branding into themes
  • select the theme through an environment variable

This meant that at build time, the correct theme would be compiled into the application.

As a result we produced two deployments from the same monorepo:

  • one deployment for betking.com
  • one deployment for supersportbet.com

Why this approach was important

I deliberately chose build-time brand configuration because brand mistakes are highly visible.

If the wrong brand theme appears even briefly, it can undermine customer trust.

By resolving branding at build time, we removed that risk entirely.

Implementing Multi-Language Support

Language requirements were different from branding.

Languages need flexibility because the same brand may operate in many countries.

For this reason I helped design the solution so that locale is resolved at runtime.

Locale from the URL

Locale is derived from the URL path.

For example:

/en-NG
/fr

The application reads the locale from the path and loads the appropriate translations.

Fallback Strategy

If a locale is missing or unsupported, we fall back to English.

English was selected because it is widely understood in the markets where the solution operates.

This ensured the user experience always remained functional.

Introducing the Discrimination ID

As the solution expanded to support multiple brands, languages, and devices, I introduced a concept we called the Discrimination ID.

The Discrimination ID combines three pieces of runtime context:

  • Brand
  • Locale
  • Device type (Web, iOS, Android)

This identifier became the single source of truth for request context.

Runtime Context Resolution

When a request enters the solution, the Discrimination ID is derived from three signals:

ContextSource
BrandBase URL (betking.com or supersportbet.com)
LocaleURL path
DeviceRequest headers / user agent

These values are combined to form the Discrimination ID.

Simplifying Frontend–Backend Integration

One of the benefits of introducing the Discrimination ID was simplifying communication between the frontend and backend.

Without it, every API request would need to include parameters such as:

  • brand
  • locale
  • device

Instead, the frontend can call the same endpoint and the backend automatically understands the context using the Discrimination ID.

Example: Registration Form

A good example is the registration flow.

When the frontend requests location data, such as available cities, the backend uses the Discrimination ID to determine:

  • which market rules apply
  • which cities should be suggested
  • which defaults should be used

This significantly reduced the complexity of frontend requests and made backend behaviour easier to manage.

Analytics Improvements

The Discrimination ID also improved analytics.

Because every event included the same context identifier, we could easily analyse metrics by:

  • brand
  • country or locale
  • device type

For example we could quickly determine:

  • registrations per brand
  • registrations per country
  • registration behaviour by device (Android, iOS, web)

Safely Migrating to the New Solution

The introduction of locale-based routing meant the new solution behaved differently from the original system.

The previous setup did not include locale in the URL.

To avoid disrupting users, I helped design a controlled rollout strategy.

Controlled Rollout with Cookie Gating

The new solution was deployed to production but only activated when a specific cookie was present.

Routing logic was implemented so that:

if cookie == true
    route user to new locale-aware system
else
    route user to existing system

This allowed:

  • developers
  • QA engineers

to test the new solution in production using real data without exposing it to all users.

Gradual Production Rollout

Once the solution proved stable, we began gradually rolling it out.

The rollout process was:

  1. start with registration
  2. enable the solution for a percentage of users
  3. monitor successful registrations
  4. expand rollout to additional parts of the application
  5. eventually reach 100% traffic

This approach ensured a safe and controlled migration.

The Result

The final solution allowed Kingmakers to support:

  • multiple brands
  • multiple languages
  • multiple device types

—all from a single front-end monorepo.

Key benefits included:

  • one shared codebase
  • deterministic brand configuration
  • flexible runtime localisation
  • simplified frontend–backend integration
  • improved analytics segmentation
  • safe production rollout

Reflection

Helping design and deliver this solution was particularly rewarding because it combined:

  • architectural design
  • collaboration with business stakeholders
  • runtime context modelling
  • production rollout strategy

Most importantly, it created a foundation that allows Kingmakers to expand into new markets while maintaining a clean and maintainable front-end architecture.