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:
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_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.
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:
origin
for client-server communication.x-forwarded-host
for server-server communication.host
as a fallback for server-server communication ifx-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: