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. A SitecoreAI 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
siteprop 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 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.tsfile and provided by the basenextjstemplate, loads the configured site fromconfig.sitecoresiteNameandconfig.defaultLanguageusing a wildcard*hostname. By default, the values ofconfig.sitecoresiteNameandconfig.defaultLanguagecome from:-
config.sitecoreSiteName- from theSITECORE_SITE_NAMEenvironment variable, if set. Otherwise, from theconfig.appNameproperty in yourpackage.jsonfile. -
config.defaultLanguage- from theDEFAULT_LANGUAGEenvironment variable, if set. Otherwise, from theconfig.languageproperty in yourpackage.jsonfile.
-
-
The
MultisitePlugin, defined in the/src/lib/site-resolver/plugins/multisite.tsfile and provided by the Next.js Multisite add-on, loads the sites fetched at build-time based on theconfig.siteslist 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
SiteResolverbased on the requested host header. -
Sets the
sc_sitecookie with the site name value and thex-sc-rewriteheader 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.