The Next.js Multisite add-on

Version: 21.x

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.

Note

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.

Note

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:

RequestResponse
/_site_<site_name>/<path>

For example, the rewrite path for the /about page for the foo site is /_site_foo/about.

Note

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 

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.

Important

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 

The SiteResolver class resolves a site for a hostname or a site name based on the provided site information list (SiteInfo).

Note

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:

RequestResponse
“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 base nextjs template, loads the configured site from config.sitecoresiteName and config.defaultLanguage using a wildcard * hostname. By default, the values of config.sitecoresiteName and config.defaultLanguage come from:

    • For JSS 21.6.0 and later, config.sitecoreSiteName - from the SITECORE_SITE_NAME environment variable, if set. For older versions of JSS, config.jssAppName - from the JSS_APP_NAME environment variable, if set. Otherwise, from the config.appName property in your package.json file.

    • config.defaultLanguage - from the DEFAULT_LANGUAGE environment variable, if set. Otherwise, from the config.language property in your package.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 the config.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 

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 the x-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.

Tip

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 

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 

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 

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.

Do you have some feedback for us?

If you have suggestions for improving this article,