---
title: "Walkthrough: Customizing build-time static paths in JSS Next.js apps"
slug: "walkthrough--customizing-build-time-static-paths-in-jss-next-js-apps"
abstract: "Control the static paths returned for statically generated dynamic routes with custom sitemap fetchers"
---
# Walkthrough: Customizing build-time static paths in JSS Next.js apps

For very large websites with many pages, products, or articles, the static generation of all the pages might take a long time. You can reduce the build time of your static-generated application by excluding some types of pages/items from static generation.

You can achieve this by using a customized `sitemap-fetcher` in the `getStaticPaths` function to modify the list of page paths that are statically generated at build time.

This walkthrough describes how to:

- Create a custom sitemap service.
- Create custom sitemap fetchers to customize lists of static paths.

## Create a custom sitemap service

You can extend the class `GraphQLSitemapService` and the interface `GraphQLSitemapServiceConfig` to allow you to exclude a particular item type:

1. In `src/lib`, create a new file `sitemap-service.ts`.
2. In the new file, import the class `GraphQLSitemapService` and the interface `GraphQLSitemapServiceConfig` from the Sitecore Next.js SDK.

    ```csharp
    import {
        GraphQLSitemapService,
        GraphQLSitemapServiceConfig,
      } from '@sitecore-jss/sitecore-jss-nextjs';
    ```

3. Extend the `GraphQLSitemapServiceConfig`, add an additional option to the service configuration:

    ```csharp
    export interface ExtendedSitemapServiceConfig extends GraphQLSitemapServiceConfig {
        /**
        * Item with sub-paths to exclude
        */

        excludeItemId?: string;
      }
    ```

4. Sitecore Delivery Edge requires a valid ID in the search query. For those instances where you will not use the `excludeItemId` option, you will need to provide a valid, but empty, id. Declare an `emptyID` constant:

    ```text
    const emptyId = '{00000000-0000-0000-0000-000000000000}';
    ```

5. Extend the `GraphQLSitemapService` class and override the `query` getter such that, if you provide an ID for `excludeItemId` it will not return items of that type:

    ```csharp
    export class ExtendedSitemapService extends GraphQLSitemapService {
      protected get query(): string {
        return /* GraphQL */ `
          query SitemapQuery(
            $rootItemId: String!
            $language: String!
            $pageSize: Int = 10
            $hasLayout: String = "true"
            $after: String
            $excludeItemId: String = "${this.options.excludeItemId ?? emptyId}"
          ) {
            search(
              where: {
                AND: [
                  { name: "_path", value: $rootItemId, operator: CONTAINS }
                  { name: "_path", value: $excludeItemId, operator: NCONTAINS }
                  { name: "_language", value: $language }
                  { name: "_hasLayout", value: $hasLayout }
                ]
              }
              first: $pageSize
              after: $after
            ) {
              total
              pageInfo {
                endCursor
                hasNext
              }
              results {
                url {
                  path
                }
              }
            }
          }
        `;
      }
      constructor(public options: ExtendedSitemapServiceConfig) {
        super(options);
      }
    ```

    > [!note]
    > We provide `$excludeItemId: String = "${this.options.excludeItemId ?? emptyId}"` in the query parameters , as well as the condition `{ name: "_path", value: $excludeItemId, operator: NCONTAINS }` to the `s earch` query.

## Create custom sitemap fetchers to customize lists of static paths

With the new sitemap service in place, you can now add sitemap fetchers that suit your needs.

- In `src/lib/sitemap-fetcher.js`, import the necessary libraries, including your new sitemap service:

    ```javascript
    /* eslint-disable @typescript-eslint/no-var-requires */
    import { StaticPath } from '@sitecore-jss/sitecore-jss-nextjs';
    import { GetStaticPathsContext } from 'next';
    import config from 'temp/config';
    import { config as packageConfig } from '../../package.json';
    import { ExtendedSitemapService } from './sitemap-service'; // your new service
    import { ItemIds } from './constants';
    ```

You can now use the refactored sitemap fetcher to customize the list of static paths for the dynamic routes in your app.

### Fetch all pages, excluding some item types

You can use your new `ExtendedSitemapService` to create a sitemap fetcher that excludes specific item types from the list of static paths.

For example, to fetch all pages except Products:

1. In `src/lib/sitemap-fetcher.js`, implement a `RootSitemapFetcher`:

    ```csharp
    export class RootSitemapFetcher {
      private _graphqlSitemapService: ExtendedSitemapService;

      constructor() {
        this._graphqlSitemapService = new ExtendedSitemapService({
          endpoint: config.graphQLEndpoint,
          apiKey: config.sitecoreApiKey,
          siteName: config.jssAppName,
          excludeItemId: ItemIds.Products, // Exclude products
        });
      }

      async fetch(context?: GetStaticPathsContext): Promise<StaticPath[]> {
        return (process.env.EXPORT_MODE
          ? this._graphqlSitemapService.fetchExportSitemap(packageConfig.language)
          : this._graphqlSitemapService.fetchSSGSitemap(context?.locales || [])
        ).then((results) => {
          // Compensate for current bug on Delivery Edge where the root '/products' item
          // is being returned from the search query which excludes it ({ name: "_path", value: $productsItemId, operator: NCONTAINS })
          return results.filter((value) => value.params.path[0] !== 'products');
        });
      }
    }
    ```

2. Export an instance of `RootSitemapFetcher`:

    ```text
    export const rootSitemapFetcher = new RootSitemapFetcher();
    ```

3. In your the file `src/pages/[[...path]].tsx`, import the instance of the `RootSitemapFetcher`:

    ```text
    import { rootSitemapFetcher } from 'lib/sitemap-fetcher';
    ```

4. Modify / add `getStaticPaths` to use the `rootSitemapFetcher`:

    ```csharp
    export const getStaticPaths: GetStaticPaths = async (context) => {
      if (process.env.NODE_ENV !== 'development') {
        // Note: Next.js runs export in production mode
        const paths = await rootSitemapFetcher.fetch(context);

        return {
          paths,
          fallback: process.env.EXPORT_MODE ? false : 'blocking',
        };
      }

      return {
        paths: [],
        fallback: 'blocking',
      };
    };
    ```

### Fetch only products

You can use the new `ExtendedSitemapService` to fetch only a specific type of item.

For example, to fetch only Products:

1. In `src/lib/sitemap-fetcher.js`, implement a `ProductSitemapFetcher`, to only return product paths:

    ```csharp
    export class ProductSitemapFetcher {
      private _graphqlSitemapService: ExtendedSitemapService;

      constructor() {
        this._graphqlSitemapService = new ExtendedSitemapService({
          endpoint: config.graphQLEndpoint,
          apiKey: config.sitecoreApiKey,
          siteName: config.jssAppName,
          rootItemId: ItemIds.Products, // Only products
        });
      }

      async fetch(context?: GetStaticPathsContext): Promise<StaticPath[]> {
        return (process.env.EXPORT_MODE
          ? this._graphqlSitemapService.fetchExportSitemap(packageConfig.language)
          : this._graphqlSitemapService.fetchSSGSitemap(context?.locales || [])
        ).then((results) => {
          results.forEach((value) => {
            value.params.path.shift(); // Remove the leading 'products' path fragment
          });
          return results;
        });
      }
    }
    ```

2. Export an instance of the fetcher:

    ```text
    export const productSitemapFetcher = new ProductSitemapFetcher();
    ```

3. In the file `src/pages/products/[[path]].tsx`, import the instance of the `ProductSitemapFetcher`:

    ```text
    import { productSitemapFetcher } from 'lib/sitemap-fetcher';
    ```

4. Modify / add the `getStaticPaths` function to use the `productSitemapFetcher`:

    ```csharp
    export const getStaticPaths: GetStaticPaths = async (context) => {

      if (process.env.NODE_ENV !== 'development') {
          // Note: Next.js runs export in production mode
          const paths = await productSitemapFetcher.fetch(context);

          return {
            paths,
            fallback: process.env.EXPORT_MODE ? false : 'blocking',
          };
        }

        return {
          paths: [],
          fallback: 'blocking',
        };
      };
    ```