The Next.js Multisite add-on
The Next.js Multisite add-on includes an example setup for hosting multiple sites from a single Next.js application. It uses Next.js Middleware to serve the correct Sitecore site based on the incoming hostname.
You add this add-on using the JSS initializer. An XM Cloud project based on a foundation template automatically includes this add-on.
This add-on includes the following:
-
A build-time JSS config plugin for multisite that fetches site information from Sitecore.
-
A Site Resolver plugin for multisite.
-
A Next.js Middleware plugin for multisite that rewrites to the correct site based on hostname.
-
A Page Props Factory plugin for multisite that sets the
site
prop based on the rewrite path.
Architecture
The following diagram shows the general flow when using the Next.js multisite add-on:
The application fetches site information from Sitecore Experience Edge during the build process using a JSS config
plugin. The site information includes each configured site's name, hostname, default language, and other site properties.
If you configure internationalized routing in your application, the route determines the current language, and your site's default language is the fallback language. The application uses the site's default language if you don't use internationalized routing.
When a visitor requests a page, the MultisiteMiddleware
uses that site information ( SiteResolver.getByHost
) to determine the site based on the requested hostname and then rewrites to the site rewrite path. The Next.js app parses the site rewrite path to get the correct site information. It then uses this site to fetch layout data, dictionary data, and so on.
The application fetches site information at build-time, not runtime, for performance reasons. Every request invokes all Next.js middleware. Because new site additions are infrequent, fetching site information at runtime (while technically possible) is not the best solution due to the potential impact on performance for the visitor. You can automate this process using a webhook to trigger automatic redeployments of your Next.js app on publish.
Understanding the site rewrite path
The Multisite add-on uses a rewrite path to identify the site.
This site rewrite path is:
-
Set by Multisite Middleware to the resolved site.
-
Read by the Next.js app for fetching layout data, dictionary data, and so on.
-
Used to enable static generation of multiple sites.
The Next.js SDK and Next.js Multisite add-on encapsulate this logic, so you don't have to manipulate this path directly. However, understanding it can assist you when troubleshooting or making customizations.
The structure of the site rewrite path is as follows:
/_site_<site_name>/<path>
For example, the rewrite path for the /about
page for the foo
site is /_site_foo/about
.
If you implemented a specific page, such as about.tsx
, while also using the catch-all route, you must exclude the page route ( /about
) from the middleware execution to prevent it from triggering the catch-all route. You can exclude the route from middleware execution by modifying the matcher rules in the src/middleware.ts
file or updating the return value of the excludeRoute
function in the src/lib/middleware/plugins/multisite.ts
file.
APIs
The Next.js Multisite add-on uses the following APIs:
GraphQLSiteInfoService
GraphQLSiteInfoService
The GraphQLSiteInfoService
fetches a list of configured site information (SiteInfo
) from Sitecore using your GraphQL Edge endpoint. The site information includes the site name, hostname, and default language.
You configure site information using SXA site definition fields.
The service fetches only SXA-based sites and includes no config-based site definitions.
The Next.js Multisite add-on provides a JSS config plugin in the /scripts/config/plugins/multisite.ts
file that uses the GraphQLSiteInfoService
to retrieve site information and then stores them in the generated src/temp/config
file in the sites
property.
SiteResolver
SiteResolver
The SiteResolver
class resolves a site for a hostname or a site name based on the provided site information list (SiteInfo
).
To resolve a site by its hostname, the SiteResolver
class uses the getByHost
method. This method accepts a string containing one or more hostnames separated by |
, ,
, or ;
). It also accepts wildcards (*
).
The getByHost
method prioritizes specific hostnames over generic/wildcard hostnames:
“order.eu.site.com” → “*.eu.site.com” → "*.site.com” → “*”
If there are multiple sites with the same hostname defined, the method prioritizes the first found.
The list of site information is collected using SiteResolver
plugins and then provided to a singleton implementation in your application. The app uses the singleton implementation, defined by default in the /src/lib/site-resolver/index.ts
file, whenever it requires a site lookup, for example, for lookups by name in the Page Props Factory or by hostname in MultisiteMiddleware
.
There are two SiteResolver
plugins involved in the site collection process:
-
The
DefaultPlugin
, defined in the/src/lib/site-resolver/plugins/default.ts
file and provided by the basenextjs
template, loads the configured site fromconfig.sitecoresiteName
andconfig.defaultLanguage
using a wildcard*
hostname. By default, the values ofconfig.sitecoresiteName
andconfig.defaultLanguage
come from:-
For JSS 21.6.0 and later,
config.sitecoreSiteName
- from theSITECORE_SITE_NAME
environment variable, if set. For older versions of JSS,config.jssAppName
- from theJSS_APP_NAME
environment variable, if set. Otherwise, from theconfig.appName
property in yourpackage.json
file. -
config.defaultLanguage
- from theDEFAULT_LANGUAGE
environment variable, if set. Otherwise, from theconfig.language
property in yourpackage.json
file.
-
-
The
MultisitePlugin
, defined in the/src/lib/site-resolver/plugins/multisite.ts
file and provided by the Next.js Multisite add-on, loads the sites fetched at build-time based on theconfig.sites
list after the configured site.
Adding the configured site first ensures it has higher priority than fetched sites with wildcard hostnames. This is helpful during your application's development stage when you have not set up hosting yet, and multiple sites are using a wildcard. After you configure more specific hostnames, those will be preferred instead.
MultisiteMiddleware
MultisiteMiddleware
The MultisiteMiddleware
Next.js Middleware handler rewrites to the appropriate Sitecore site based on a hostname. The middleware plugin uses the multisite middleware handler defined in the /src/lib/middleware/plugins/multisite.ts
file.
The MultisiteMiddleware
middleware handler:
-
Resolves sites with the
SiteResolver
based on the requested host header. -
Sets the
sc_site
cookie with the site name value and thex-sc-rewrite
header with the value of the rewritten path, which can be reused by following middleware. -
Rewrites the response to the specific site using the site rewrite path.
Suppose you do not have a dedicated domain for each site, such as Vercel Preview URLs. In that case, you can force the application to use a specific site by specifying the sc_site
query string parameter—for example, https://foo.site.com?sc_site=bar
.
The sc_site
cookie will be used for subsequent requests while browsing the site, so you do not need to append this for every request. This behavior is configured by the useCookieResolution
option. Only Vercel Preview Deployments (where process.env.VERCEL_ENV === 'preview'
) enable the useCookieResolution
option by default.
normalizeSiteRewrite
normalizeSiteRewrite
The normalizeSiteRewrite
function removes site data from a site rewrite path (for example, so the application can appropriately retrieve layout data). It is used by the multisite path extraction plugin in the /src/lib/extract-path/plugins/multisite.ts
file.
getSiteRewriteData
getSiteRewriteData
The getSiteRewriteData
function extracts site data (site_name
) from a rewrite path. It is utilized in the multisite Page Props Factory plugin in the /src/lib/page-props-factory/plugins/site.ts
file.
MultisiteGraphQLSitemapService
MultisiteGraphQLSitemapService
The MultisiteGraphQLSitemapService
is used to fetch the list of pages for static generation for multiple sites.
Limitations
The Next.js Multisite add-on has the following limitations:
-
Virtual folders are not supported when the publishing target is Experience Edge, because they are excluded from the Edge publishing logic.
-
Site information is fetched only at build time. The application must be rebuilt if a new site is added or the hostname is modified.
-
Config-based site definitions are not currently included. Only SXA-based sites will be fetched.
-
Next.js i18n domain routing and automatic locale detection were not necessarily intended for multisite scenarios. For example, you cannot have multiple domains mapped to the same default locale. If you run into limitations, remember you can also serve sites using a dedicated rendering host (a single site).
-
404 and 500 custom error pages are not currently supported. Instead, use the default error pages.