---
title: "The Next.js Multisite add-on"
slug: "the-next-js-multisite-add-on"
abstract: "The Next.js Multisite add-on includes an example setup for hosting multiple sites from a single Next.js application."
---
# 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](https://nextjs.org/docs/advanced-features/middleware) to serve the correct Sitecore site based on the incoming hostname.

You add this add-on using the [JSS initializer](https://doc.sitecore.com/xmc/en/developers/jss/217/jss-xmc/en/the-jss-app-initializer.html). 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](https://nextjs.org/docs/advanced-features/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](https://doc.sitecore.com/sai/en/developers/jss/22/jss-sai/internationalized-routing-in-jss-next-js-apps.html "Internationalized routing in JSS Next.js apps") 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](https://doc.sitecore.com/sai/en/developers/jss/22/jss-sai/deploy-your-front-end-application-to-vercel.html "Deploy your front-end application to Vercel").

![nextjs-multisite-addon-architecture.png](https://doc.sitecore.com/api/markdown-image/sai/en/developers/jss/22/jss-sai/images/nextjs-multisite-addon-architecture.png)

## 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:

```plaintext
/_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.
>
> The default matcher in `src/middleware.ts` matches all paths except `/api` (API routes), `/_next` (Next.js internals), `/sitecore/api` (Sitecore API routes), `/-` (Sitecore media), `/healthz` (health check), and all root files inside the `public` folder.

## 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](https://doc.sitecore.com/xp/en/developers/sxa/104/sitecore-experience-accelerator/en/the-sxa-site-definition-fields.html).

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:
>
> “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:
    - `config.sitecoreSiteName` - from the `SITECORE_SITE_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](https://nextjs.org/docs/advanced-features/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](https://vercel.com/docs/concepts/deployments/preview-deployments#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](https://vercel.com/docs/concepts/deployments/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](https://doc.sitecore.com/sai/en/developers/jss/22/jss-sai/the-next-js-multisite-add-on.html#UUID-2d3328d8-eeac-9dca-4cb7-d086cf58a2dd_section-idm1403006226426923 "Understanding the site 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](https://doc.sitecore.com/xp/en/developers/hd/22/sitecore-headless-development/en/preparing-the-list-of-pages-for-static-generation-or-export-in-jss-next-js-apps.html). 

## 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](https://nextjs.org/docs/advanced-features/i18n-routing#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.