Vue Storefront is now Alokai! Learn More
Multistore configuration

Multistore configuration

Multistore allows different store configurations to coexist within a single Storefront and Server Middleware instance.

How it works?

Multi-store is an agnostic extension for Middleware that adjusts configuration depending on the incoming request's address.

The storefront is using @vue-storefront/multistore package to handle the multistore configuration and adjust the configuration based on the incoming request's address.

To learn more about the details of this solution, see the Multistore Extension section of this page.

How to start?

Let's assume that you have a different store for specific countries where you sell your products. Each store has its domain:

  • en.mycommerce.com
  • de.mycommerce.com

1. Middleware configuration

In the Alokai Storefront, the multistore configuration is located in the apps/storefront-middleware/multistore.config.ts file.

You need to define configuration differences for each of stores under those domains:

// apps/storefront-middleware/multistore.config.ts

// In this example we're using SAPCC as the selected e-commerce platform
import type { Config } from "./integrations/sapcc";
import dotenv from "dotenv";
import { resolve } from "node:path";
import { defineConfig, getRequiredEnv } from "./multistore/utils/defineConfig";

dotenv.config({ path: resolve(__dirname, ".env") });

export const config = defineConfig<Config>({
  "dev.vsf.local": {},
  "dev.client.local": {},
  "en.mycommerce.com": {
    // different config for store under this domain, for e.g. in SAPCC
    api: {
      // if you're setting the required values - use getRequiredEnv helper
      // that checks in runtime if the value is really set
      baseSiteId: getRequiredEnv("MULTISTORE1_BASE_SITE_ID"),
      // for non-required values you still can use process.env
      catalog: process.env.MULTISTORE1_CATALOG,
    }
  },
  "de.mycommerce.com": {
    api: {
      baseSiteId: getRequiredEnv("MULTISTORE2_BASE_SITE_ID"),
      catalog: process.env.MULTISTORE2_CATALOG,
    }
  },
});

Where from I should know what to modify for each domain?

Generally you need to know the differences between the store configured at e-commerce platform of your choice. Sometimes it just one parameter that points to the store, like channelID in BigCommerce. In other system it could be a few parameters like: store ID, catalog ID and the available currency. Sometimes some differences will be not required by the e-commmerce platform but by yourself, for e.g. the different configuration of the faceting.

More example you can find in the section: E-commerce platforms

2. Web server

Now we're going to install an extra software needed to run multistore - the caddy webserver. Visit the official documentation to read about the installation process on your operating system.

3. DNS

For the browser to find the entered domain addresses we use, a DNS server is needed. We can use the built-in server in most operating systems. Its configuration is done by editing the /etc/hosts file. In the Windows system, it is located in the C:\Windows\System32\drivers\etc directory. In most cases, editing it requires administrator privileges.

In our example, we will use MacOS and the command-line editor nano.

sudo nano /etc/hosts

Then edit the contents of the file by adding two entries for our domains.

##
# Host Database
#
# localhost is used to configure the loopback interface
# when the system is booting.  Do not change this entry.
##
127.0.0.1       localhost
+127.0.0.1       en.mycommerce.com
+127.0.0.1       de.mycommerce.com

4. Generate extra files

To run the caddy we need configuration file. Don't worry our scripts prepare it for you, all you need is just to run this in the root directory of your project:

yarn run multistore:init

5. Run Multistore

You're ready to go! Now first start the caddy server by run a command in the root directory of the project:

caddy run

Windows + WSL

On Windows with WSL, run the caddy from Windows not from WSL. Caddy on the first run installs the own SSL certificates, so it must be installed on host operating system. To access the configuration file, you could navigate on PowerShell to the \\WSL$\Distro where Distro is your WSL distribution name. If you don't know the name of your WSL distribution, run:

wsl --list --verbose

When caddy is running, now in a separate terminal just start the Multistore using a proper command in root directory of your project:

Next
yarn multistore:dev:next

Multistore is now running - try to open browser at one of configured domains using the https:// protocol i.e. https://de.mycommerce.com.

Production deployment

When deploying the Storefront to Alokai Cloud, go to the Console and set the IS_MULTISTORE_ENABLED environment variable in Middleware to true. Also set the appropriate values for the frontend:

Next
NEXT_PUBLIC_ALOKAI_MIDDLEWARE_API_URL="http://additional-app-middleware:4000"
NEXT_PUBLIC_ALOKAI_MIDDLEWARE_SSR_API_URL="http://additional-app-middleware:4000"
NEXT_PUBLIC_ALOKAI_MULTISTORE_ENABLED=true

Last, but not least, we highly recommend using the http://<pod-name>:<port> as the base URL for the API in the storefront configuration. This way, the communication done during SSR will be done using the internal network, which is faster and more secure. Typically, it would be http://additional-app-middleware:4000.

E-commerce platforms

SAP

SAP requires several configuration keys per store. To handle multiple stores in SAP, you need to configure the configuration.api for each domain.

Example:

We have a default configuration for SAPCC that offers apparel products.

/integrations/sapcc/config.ts
export const sapccConfig = {
  location: "@vsf-enterprise/sapcc-api/server",
  configuration: {
    OAuth: {
      uri: SAPCC_OAUTH_URI,
      clientId: SAPCC_OAUTH_CLIENT_ID,
      clientSecret: SAPCC_OAUTH_CLIENT_SECRET,
      tokenEndpoint: SAPCC_OAUTH_TOKEN_ENDPOINT,
      tokenRevokeEndpoint: SAPCC_OAUTH_TOKEN_REVOKE_ENDPOINT,
      cookieOptions: {
        "vsf-sap-token": { secure: NODE_ENV !== "development" },
      },
    },
    api: {
      uri: SAPCC_API_URI,
      baseSiteId: "apparel-uk",
      catalogId: "apparelProductCatalog",
      catalogVersion: "Online",
      defaultLanguage: "en",
      defaultCurrency: "USD",
    },
  },
  extensions: (extensions: ApiClientExtension[]) => [
    ...extensions,
    ...(IS_ALGOLIA_ENABLED ? [unifiedApiExtensionWithAlgolia] : [unifiedApiExtension]),
    ...(IS_MULTISTORE_ENABLED ? [multistoreExtension] : []),
  ],
} satisfies Integration<MiddlewareConfig>;

We want to add a separate store for electronics products.

// apps/storefront-middleware/multistore.config.ts

// In this example we're using SAPCC as the selected e-commerce platform
import type { Config } from "./integrations/sapcc";
import dotenv from "dotenv";
import { resolve } from "node:path";
import { defineConfig, getRequiredEnv } from "./multistore/utils/defineConfig";

dotenv.config({ path: resolve(__dirname, ".env") });

export const config = defineConfig<Config>({
  "dev.vsf.local": {},
  "dev.client.local": {},
  "en.mycommerce.com": {
    api: {
      baseSiteId: getRequiredEnv("MULTISTORE1_BASE_SITE_ID"),
    }
  },
  "de.mycommerce.com": {
    api: {
      baseSiteId: getRequiredEnv("MULTISTORE2_BASE_SITE_ID"),
    }
  },
});

Now, the pl.mycommerce.com domain will use the apparel-uk configuration and the de.mycommerce.com domain will use the electronics configuration.

SFCC

To handle multiple stores in SFCC, you need to configure the origin and siteId for each domain, as was described in this guide.

// apps/storefront-middleware/multistore.config.ts

import type { Config } from "./integrations/sapcc";
import dotenv from "dotenv";
import { resolve } from "node:path";
import { defineConfig, getRequiredEnv } from "./multistore/utils/defineConfig";

dotenv.config({ path: resolve(__dirname, ".env") });

export const config = defineConfig<Config>({
  "dev.vsf.local": {},
  "dev.client.local": {},
  "en.mycommerce.com": {
    origin: getRequiredEnv('MULTISTORE1_ORIGIN'),
    siteId: getRequiredEnv('MULTISTORE1_SITE_ID'),
  },
  "de.mycommerce.com": {
    origin: getRequiredEnv('MULTISTORE2_ORIGIN'),
    siteId: getRequiredEnv('MULTISTORE2_SITE_ID'),
  },
});

BigCommerce

BigCommerce offers a multistorefront feature, which requires to configure the channelId for each domain.

In case, you'd need to handle multiple separate BigCommerce stores, you need to configure whole integration for each store separately.

// apps/storefront-middleware/multistore.config.ts

import type { Config } from "./integrations/sapcc";
import dotenv from "dotenv";
import { resolve } from "node:path";
import { defineConfig, getRequiredEnv } from "./multistore/utils/defineConfig";

dotenv.config({ path: resolve(__dirname, ".env") });

export const config = defineConfig<Config>({
  "dev.vsf.local": {},
  "dev.client.local": {},
  "en.mycommerce.com": {
    channelId: getRequiredEnv('MULTISTORE1_CHANNEL_ID'),
  },
  "de.mycommerce.com": {
    channelId: getRequiredEnv('MULTISTORE2_CHANNEL_ID'),
  },
});

Commercetools

In Commercetools, you may need to configure the channel for each domain.

// apps/storefront-middleware/multistore.config.ts

import type { Config } from "./integrations/sapcc";
import dotenv from "dotenv";
import { resolve } from "node:path";
import { defineConfig, getRequiredEnv } from "./multistore/utils/defineConfig";

dotenv.config({ path: resolve(__dirname, ".env") });

export const config = defineConfig<Config>({
  "dev.vsf.local": {},
  "dev.client.local": {},
  "en.mycommerce.com": {
    channel: getRequiredEnv('MULTISTORE1_CHANNEL'),
  },
  "de.mycommerce.com": {
    channel: getRequiredEnv('MULTISTORE2_CHANNEL'),
  },
});

Multistore Extension

How it works?

This approach assumes that each store has its domain. The extension uses the domain name to fetch the store-specific configuration. The configuration is then merged with the base configuration. The fetched configuration is cached to avoid unnecessary requests.

Prerequisites

Ensure the following prerequisites are met for the unified multistore solution:

  • It works within the Alokai infrastructure.
  • Requires three headers for proper functionality:
    1. origin for client-server communication.
    2. x-forwarded-host for server-server communication.
    3. host as a fallback for server-server communication if x-forwarded-host is absent.
  • The client communicating with the middleware must include these headers in requests.

Architectural Overview

To understand how the multistore solution works, see the following diagrams:

C4 diagram: Middleware component level

System component level

Sequence diagram

Sequence diagram