1. Sitecore Content SDK

Upgrade JSS 22.0 Next.js apps to Content SDK 2.1

Version:

Content SDK is a major upgrade from previous versions of Sitecore JavaScript Services SDK (JSS) for SitecoreAI. It reduces the size and complexity of starter applications, removing redundant functionality not needed for SitecoreAI implementations. As a result, Content SDK applications are easier to understand and maintain than apps built with JSS.

This comprehensive guide covers all the changes you must make to your existing JSS 22.0 applications to migrate to Content SDK 2.1. However, because of the nature of JavaScript and Next.js application development, this guide doesn't account for all the customization you might have in your existing application.

While upgrading, consider the JSS templates and add-ons you used when creating your Next.js JSS application. You can find them in your package.json file. For example, a JSS 22.0 application based on the XM Cloud starter kit uses the following templates and add-ons, so this guide assumes your app includes all of them:

  • nextjs

  • nextjs-xmcloud

  • nextjs-sxa

  • nextjs-multisite

XM Cloud is now SitecoreAI

Some code examples, images, and UI labels may still use XM Cloud while engineering assets are being updated.

Before you begin
  • If you haven't already done so, upgrade your app to JSS 22.0.0.

  • We recommend you read the official release notes for React 19 and Next.js 16 to understand what has changed in these new versions.

  • Familiarize yourself with the JSS and Content SDK changelogs. If your application is heavily customized, the changelog can provide guidance on what additional changes you need that are not covered in this topic.

This topic covers the following subjects:

What's new in Content SDK?

Here's a short overview of the changes introduced in Content SDK:

  • Includes out-of-the-box support for the Design Studio that serves as a centralized interface to help teams visualize and test components across their organization.

  • Three brand new site templates in addition to the classic Skatepark template.

  • A new file, sitecore.config.ts, serves as the central point for configuring your application's build and run time.

  • Another new file, sitecore.cli.config.ts, used to configure CLI commands for Content SDK that enable it to replace build-time and dev tools scripts.

  • The new Sitecore Client Data Fetching API, represented by the SitecoreClient class, unifies all data fetching logic and replaces the previous data fetching plugins.

  • A new utility named defineProxy (previously called defineMiddleware in Content SDK version 1.5 and earlier), simplifies proxy composition and provides better visibility by removing the need for proxy plugins.

  • Supports the enhanced SitecoreAI page builder in place of the Sitecore Experience Editor.

  • Analytics, event tracking, and personalization support out of the box.

Update application dependencies through all versions

For your upgraded application to work correctly, you will need to update dependencies.

To update your dependencies:

  1. In your existing application's package.json file, update packages progressively:

    • Remove any dependencies that start with @sitecore-cloudsdk/ and add the following:

      "@sitecore-content-sdk/analytics-core": "^2.0.0",
      "@sitecore-content-sdk/personalize": "^2.0.0",
      "@sitecore-content-sdk/events": " ^2.0.0",
      Note

      See the Cloud SDK integration section for further steps to complete the migration from @sitecore-cloudsdk to the Content SDK packages.

    • Update @types/node to version ^24.10.4.

    • Update @typescript-eslint/eslint-plugin to version ^8.14.0.

    • Update @typescript-eslint/parser to version ^8.14.0.

    • Update eslint to version ^8.56.0. In Content SDK 1.1 and higher, ESLint 9 is the default linter, but you can continue using the older one or optionally upgrade to ESLint 9.

    • Update typescript to version ~5.4.0.

    • Install [email protected] for improved memory usage using the following command:

    • Update React and Next.js:

      "next": "^16.1.1", 
      "react": "^19.1.0", 
      "react-dom": "^19.1.0", 
      "@types/react": "^19.1.2", 
      "@types/react-dom": "^19.1.3", 
      "eslint-plugin-react": "^7.37.5"
    • Update @sitecore-feaas/clientside to version ^0.6.0.

    • Update @sitecore/components to version ~2.1.0.

    • Replace @sitecore-jss/sitecore-jss-nextjs with @sitecore-content-sdk/nextjs. Set the version to ^2.0.0.

    • Replace all references to @sitecore-jss/sitecore-jss-nextjs with @sitecore-content-sdk/nextjs throughout your application.

    • Replace @sitecore-jss/sitecore-jss-cli with @sitecore-content-sdk/cli. Set the version to ^2.0.0.

    • Delete @sitecore-jss/sitecore-jss-dev-tools.

  2. Install dependencies with the following command:

    npm install
  3. Update your ESLint configuration by making the following changes to the .eslintrc file:

    "@typescript-eslint/no-unused-vars": [ 
      "error", 
      { 
        "caughtErrorsIgnorePattern": "." 
      } 
    ],
  4. Make the following changes to tsconfig.json:

    • Add above the lib entry:

      ... 
      "types": ["node"], 
      ... 
    • Delete the following from compilerOptions.paths:

      "graphql-types": ["node_modules/@types/graphql-let/__generated__/__types__"],

Create a Content SDK 2.1 application

To simplify the upgrade process as much as possible, create a Content SDK application. You can then copy some files from this template app into your existing app.

To create a Next.js Content SDK application:

  1. In a console, run the following command:

  2. If prompted to install the [email protected] package, answer y.

  3. Enter the folder path for the new app. For example, enter ./content-sdk-template, to create the named subfolder in your current working directory.

  4. When prompted, choose the same prerendering method (SSG or SSR) as used in your existing JSS application.

The script then installs the application dependencies.

Update the SXA add-on

The Content SDK template has a lean footprint. It doesn’t have components that were previously available in the JSS starter kit. To use those components, the recommended approach is to copy them from Content SDK starter kit. Note that if you’ve customized your components in JSS, you must replicate them in the Content SDK versions too.

To update the SXA add-on:

  1. Replace the following files with the new versions from the starter kit:

    • src/components/Image.tsx

    • src/components/Promo.tsx

    • src/components/Title.tsx

    • src/assets/sass/components/title/_component-title.scss

  2. Update the following SASS files:

    • src/assets/sass/components/_component-column-splitter.scss:

      padding-left: $default-padding * 0.5; 
      padding-right: $default-padding * 0.5;
    • In /src/assets/sass/components/promo/_promo-shadow.scss, reposition CSS statements above the @include respond-to(all-mobile) block:

      ... 
        >.component-content { 
          padding: 15px; 
          margin: 0 0 30px 0; 
          @include respond-to(all-mobile) { 
            margin: 0 10px 30px 10px; 
          } 
          &:before, &:after { 
            ... 
       
      
      src/lib/next-config/plugins/sass.js: 
      
      sassOptions: { 
        ... 
        quietDeps: true, 
        silenceDeprecations: ["import", "legacy-js-api"], 
      },

Disable automatic GraphQL code generation

To disable automatic GraphQL code generation:

  1. Remove the following dependencies from package.json:

    "@graphql-typed-document-node/core": "^3.2.0", 
    "graphql-let": "^0.18.6", 
    "graphql": "~15.8.0", 
    "graphql-tag": "^2.12.6", 
    "@graphql-codegen/cli": "^5.0.0", 
    "@graphql-codegen/import-types-preset": "^3.0.0", 
    "@graphql-codegen/plugin-helpers": "^5.0.1", 
    "@graphql-codegen/typed-document-node": "^5.0.1", 
    "@graphql-codegen/typescript": "^4.0.1", 
    "@graphql-codegen/typescript-operations": "^4.0.1", 
    "@graphql-codegen/typescript-resolvers": "^4.0.1",
  2. Remove the graphql:update script and remove graphql-let reference from bootstrap script:

    "bootstrap": "ts-node --require dotenv-flow/config --project tsconfig.scripts.json scripts/bootstrap.ts",
  3. Delete the following files:

    • .graphql-let.yml

    • /scripts/fetch-graphql-introspection-data.ts

    • /src/temp/GraphQLIntrospectionResult.json

Update existing forms to use the new wrapper

To update existing forms:

  1. In Content Editor, select the page containing the existing form.

  2. Click Presentation > Details.

  3. In the Final Layout tab, click Edit under Headless Layout.

  4. Select the BYOC Wrapper control and click Change.

  5. Select Feature > Headless Experience Accelerator > Forms > Form and click Select.

  6. Click Edit.

  7. Copy the formId from the Component Name parameter (only the value after ?formId=).

  8. Paste it into the FormId field at the top.

  9. Delete all items in the Parameters section.

  10. Click OK.

  11. Repeat for all forms.

When all forms are updated, remove the following from /src/byoc/index.client.tsx:

import '@sitecore/components/form';

Migrate to Content SDK architecture

The following sections explain how to synchronize files in your existing JSS application with corresponding files from your Content SDK template app. This also includes steps to complete the Next.js 16 upgrade, Cloud SDK integration, React 19 refactor, and update other template files.

Update configurations and environment variables

This section updates your existing app's configurations and environment variables to match the new Content SDK app.

To update your JSS app's configurations and environment variables:

  1. Copy the following files from the template app into your existing app:

    • sitecore.config.ts

    • src/Providers.tsx

    • src/Bootstrap.tsx

  2. Throughout your app, replace all imports of config from temp/config and use the new sitecore.config.ts file instead:

    • Locate all instances of the following:

      import config from 'temp/config'
    • Replace these with the following:

      import scConfig from 'sitecore.config'
  3. A new page parameter has been added to SitecoreContext. To support this change, update the SitecoreContext API configuration in the following files:

    • [[...path]].tsx

    • 500.tsx

    • 404.tsx

    In each file, set the api parameter to use scConfig.api and the page parameter to use page as shown in the following example:

    import scConfig from 'sitecore.config'; 
    ... 
    const page = client.getPage(...); 
    <SitecoreContext 
      ... 
      api={scConfig.api} 
      page={page} 
    >
  4. Rename the following environment variables within your JSS app:

    Old (JSS)

    New (Content SDK)

    SITECORE_API_KEY

    NEXT_PUBLIC_SITECORE_API_KEY

    SITECORE_API_HOST

    NEXT_PUBLIC_SITECORE_API_HOST

    SITECORE_SITE_NAME

    NEXT_PUBLIC_DEFAULT_SITE_NAME

    DEFAULT_LANGUAGE

    NEXT_PUBLIC_DEFAULT_LANGUAGE

    JSS_EDITING_SECRET

    SITECORE_EDITING_SECRET

  5. If your application currently depends on SITECORE_EDGE_URL, remove all instances of SITECORE_EDGE_URL from env files and deployment configurations. Set the following new variable(s) to the same value and restart the app. Rebuild for Next.js so that NEXT_PUBLIC_* is in the client bundle.

    • NEXT_PUBLIC_SITECORE_EDGE_PLATFORM_HOSTNAME - for Next.js projects so both server and client use the custom host.

    • SITECORE_EDGE_PLATFORM_HOSTNAME - non Next.js or server only

    If you have explicitly configured edgeUrl in sitecore.config, set it to the following:

    edgeUrl: process.env.NEXT_PUBLIC_SITECORE_EDGE_PLATFORM_HOSTNAME || 'https://edge-platform.sitecorecloud.io', 

    For non‑Next.js environments, mirror this pattern with the SITECORE_EDGE_PLATFORM_HOSTNAME variable instead.

    Note

    Newly scaffolded apps use defineConfig() and get edgeUrl from the new environment variable automatically, so you might not have the edgeUrl section under edge.

    The default value of <https://edge-platform.sitecorecloud.io> is used unless you use the new variables.

    SITECORE_EDGE_CONTEXT_ID does not need to be renamed unless you need client-side access.

    If needed, create NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID with the same value. Doing this will expose your context ID secret on the client.

  6. If your existing app uses DISABLE_SSG_FETCH rename it to GENERATE_STATIC_PATHS.

    Note

    The meaning and value of this variable has been logically inverted. If your existing solution uses this variable in the code, you must adjust them accordingly.

  7. Copy the src/lib/sitecore-client.ts file from your template app into the same folder in your existing JSS app.

  8. Middleware has been renamed to proxy in Next.js 16 to better reflect its purpose. Instead of Next.js discovering middleware automatically by filename, it now runs the proxy.ts file directly. Refactor all Next.js middleware in your existing app to use the new defineProxy utility:

    • Create src/proxy.ts. Add your proxy logic here. The file must export a single function (default export or named proxy) that accepts a NextRequest and returns the result of the proxy chain as shown:

      export default function proxy(req: NextRequest) { 
          // ... create locale, multisite, redirects, personalize instances ... 
          return defineProxy(locale, multisite, redirects, personalize).exec(req); 
      } 
      export const config = { matcher: [...] }; 
    • Ensure that your proxy order is correct:

      • For Next.js apps using App Router - locale → multisite → redirects → personalize

      • For Next.js apps using Pages Router - multisite → redirects → personalize

    Note

    Ensure you delete src/proxy.ts and the old src/lib/middleware/ (or equivalent) before adding src/middleware.ts with defineMiddleware, using the template as reference.

  9. Individual API route files (for sitemap, robots, editing endpoints, health) still use the Middleware classes to implement their actual behavior for those specific routes. The proxy.ts file only handles edge requests and routing behavior.

    Item

    Description

    For sitemap and robots.txt

    Use SitemapMiddleware or RobotsMiddleware from @sitecore-content-sdk/nextjs/middleware

    Editing APIs

    Use EditingConfigMiddleware, EditingRenderMiddleware, or FEAASRenderMiddleware from @sitecore-content-sdk/nextjs/editing

    Healthcheck

    Use the HealthcheckMiddleware from @sitecore-content-sdk/nextjs/monitoring

  10. In [[..path]].tsx, 404.tsx, 500.tsx, and Layout.tsx, remove all usages of headLinks.

Cloud SDK integration

The Content SDK has undergone a major architectural transformation to include functionality from the Cloud SDK. The Content SDK now includes tracking, events, and personalization.

To enable these changes:

  1. In Bootstrap.tsx:

    • Find the CloudSDK initialization logic:

      CloudSDK({  
        sitecoreEdgeUrl: config.api.edge.edgeUrl,  
        sitecoreEdgeContextId: config.api.edge.clientContextId,  
        siteName: page.siteName || config.defaultSite,  
        enableBrowserCookie: true,  
        // Replace with the top level cookie domain of the website that is being integrated e.g ".example.com" and not "www.example.com"  
        cookieDomain: window.location.hostname.replace(/^www\./, ''),  
      }) 
        .addEvents()  
        .initialize(); 
    • Replace it with the following:

      initContentSdk({  
        config: {  
          contextId: config.api.edge.clientContextId,  
          edgeUrl: config.api.edge.edgeUrl,  
          siteName: page.siteName || config.defaultSite,  
        },  
        plugins: [  
          analyticsPlugin({  
            options: {  
              enableCookie: true,  
              cookieDomain: window.location.hostname.replace(/^www\./, ''),  
            },  
            adapter: analyticsBrowserAdapter(),  
          }),  
          eventsPlugin(),  
        ],  
      }); 
    • Remove the following imports:

      import { CloudSDK } from '@sitecore-cloudsdk/core/browser'; 
      import { SitecorePageProps } from '@sitecore-content-sdk/nextjs';  
      import '@sitecore-cloudsdk/events/browser'; 
    • Add the following imports:

      import { SitecorePageProps, initContentSdk } from '@sitecore-content-sdk/nextjs';  
      import { eventsPlugin } from '@sitecore-content-sdk/events';  
      import { analyticsBrowserAdapter, analyticsPlugin } from '@sitecore-content-sdk/analytics-core'; 
  2. In CdpPageView.tsx:

    • Find the following import:

      import { pageView } from '@sitecore-cloudsdk/events/browser'; 
    • Replace it with the following:

      import { pageView } from '@sitecore-content-sdk/events'; 

You might also have to make further changes to other files that contains older Cloud SDK logic based on your implementation. See Initializing tracking, events, and personalization in the Content SDK for more information.

Refactor aligned with React 19 best practices

React logic in the Content SDK has been refactored to follow React 19 best practices. The following section outlines the breaking changes introduced by this refactor and provides examples of the new implementations.

  1. The @sitecore-content-sdk/react package introduces the following updated types and signatures:

    • useSitecore(options?: UseSitecoreOptions): SitecoreProviderState

    • SitecoreProviderState now includes:

      • page: Page

      • api?: SitecoreProviderProps['api']

      • setPage?: (value: Page) => void (renamed from updatePage)

      • componentMap: ComponentMap (new)

      • loadImportMap: () => Promise<ImportMapImport> (new)

    • PlaceholderProps is expanded to explicitly list all supported properties:

      export interface PlaceholderProps { 
        name: string; 
        rendering: ComponentRendering | RouteData; 
        componentMap?: ComponentMap; 
        page?: Page; 
        fields?: { [name: string]: Field | Item | Item[] }; 
        params?: { [name: string]: string }; 
        disableSuspense?: boolean; 
        errorComponent?: React.ComponentClass<ErrorComponentProps> | React.FC<ErrorComponentProps>; 
        hiddenRenderingComponent?: React.ComponentClass | React.FC; 
        missingComponentComponent?: React.ComponentClass | React.FC; 
        componentLoadingMessage?: string; 
        renderEmpty?: (components: React.ReactNode[]) => React.ReactNode; 
        renderEach?: (component: React.ReactNode, index: number) => React.ReactNode; 
        render?: (components: React.ReactNode[], data: ComponentRendering[], props: PlaceholderProps) => React.ReactNode; 
        passThroughComponentProps?: { [key: string]: unknown }; 
      } 

    These updates make the context shape and placeholder behavior explicit and compatible with React 19 best practices, especially for server and client components. The additional fields (componentMap, loadImportMap) support more flexible composition and lazy loading. To update your code:

    • Review all imports and usages of SitecoreProviderState and PlaceholderProps.

    • If you relied on implicit properties, update your type annotations to the new explicit interface.

    • If you used updatePage, rename it to setPage.

    • If you previously inferred types from usage, consider importing the updated types from @sitecore-content-sdk/react to align with 2.1.

    No runtime changes are required in this step beyond adjusting renamed fields.

  2. The withPlaceholder higher-order component now only accepts the component as an argument and injects a placeholders prop derived from props.rendering.placeholders.

    • Find implementations of a single placeholder:

      import { withPlaceholder, PlaceholderProps } from '@sitecore-content-sdk/react'; 
      
      type HomeProps = PlaceholderProps; 
      
      const Home: React.FC<HomeProps> = ({ pageContent }) => ( 
        <div className="home-mock">{pageContent}</div> 
      );
      export default withPlaceholder('page-content')(Home); 
    • Replace it with the following:

      import { withPlaceholder } from '@sitecore-content-sdk/react'; 
      
      type HomeProps = { 
        placeholders: Record<string, React.ReactNode>; 
      }; 
      
      const Home: React.FC<HomeProps> = ({ placeholders }) => ( 
        <div className="home-mock"> 
          {placeholders['page-content']} 
        </div> 
      ); 
      
      export default withPlaceholder(Home); 
      Important

      When rendering the wrapper on a server component in Next.js App Router while using withAppPlaceholder, you must still pass the rendering, page, and componentMap props:

      const WrappedHome = withAppPlaceholder(Home);
      <SitecoreProvider page={page} componentMap={componentMap} api={api}>
        <WrappedHome
          rendering={page.layout.sitecore.route}
          page={page}
          componentMap={componentMap}
        />
      </SitecoreProvider>;
    • If you rely on a multi-placeholder mapping as shown:

      type HomeProps = PlaceholderProps & {
        subProp?: React.ReactElement;
      };
      const Home: React.FC<HomeProps> = ({ subProp, pageContent }) => (
        <div>
          <header>{subProp}</header>
          <main>{pageContent}</main>
        </div>
      );
      export default withPlaceholder(
        [
          { placeholder: 'page-header', prop: 'subProp' },
          'page-content',
        ]
      )(Home);
    • Convert it as shown:

      type HomeProps = {
        placeholders: Record<string, React.ReactNode>;
      };
      const Home: React.FC<HomeProps> = ({ placeholders }) => (
        <div>
          <header>{placeholders['page-header']}</header>
          <main>{placeholders['page-content']}</main>
        </div>
      );
      export default withPlaceholder(Home);
  3. The withSitecore higher-order component is deprecated. The recommended alternative is the useSitecore hook.

    To update your code, find the current implementation:

    import {
      withSitecore,
      type SitecoreProviderState,
    } from '@sitecore-content-sdk/react';
    type Props = Partial<SitecoreProviderState> & { customProp: string };
    const MyComponent: React.FC<Props> = ({ page, api, setPage, customProp }) => {
      // ...
    };
    export default withSitecore({ updatable: true })(MyComponent);

    Replace it with the following:

    import { useSitecore } from '@sitecore-content-sdk/react';
    type Props = { customProp: string };
    const MyComponent: React.FC<Props> = ({ customProp }) => {
      const { page, api, setPage } = useSitecore({ updatable: true });
      // ...
    };
    Note

    If you continue using withSitecore, the updatePage prop it previously injected is now named setPage.

  4. Placeholder and AppPlaceholder are stricter and now pass only the following props to the components rendered for a placeholder:

    • Context properties (page, componentMap)

    • fields, params and rendering data

      fields: {
        [name: string]: Field<GenericFieldValue> | Item | Item[];
      };
      params: {
        [name: string]: string;
      };
      rendering: ComponentRendering;

      The modifyComponentProps callback is still available, but it should not be required for simple prop injection. For example, the following usage:

      <AppPlaceholder
        name="main"
        rendering={route}
        componentMap={components}
        page={page}
        modifyComponentProps={(props) =>
          { ...props, extraDiv: true }
        }
      />

      Can be streamlined using passThroughComponentProps as shown:

      <AppPlaceholder
        name="main"
        rendering={route}
        componentMap={components}
        page={page}
        passThroughComponentProps={{ extraDiv: true }}
      />
  5. All built-in Content SDK components that previously relied on React.forwardRef (such as RichText, Link, and others) now treat ref as a regular prop instead of using forwardRef. This change follows React 19 recommendations best practices.

    Important

    Please refer to the official React 19 upgrade guide to update other parts of your application that's not specific to the Content SDK.

  6. The SitecoreProvider component now requires the loadImportMap prop. Update the SitecoreProvider implementation as shown:

    import { 
      ComponentPropsCollection, 
      ComponentPropsContext, 
      Page, 
      SitecoreProvider, 
    } from '@sitecore-content-sdk/nextjs'; 
    import components from '.sitecore/component-map'; 
    import scConfig from 'sitecore.config'; 
    
    const Providers = ({ 
      children, 
      componentProps, 
      page, 
    }: { 
      children: React.ReactNode; 
      componentProps?: ComponentPropsCollection; 
      page: Page; 
    }) => { 
      return ( 
        <ComponentPropsContext value={componentProps || {}}> 
          <SitecoreProvider 
            componentMap={components} 
            api={scConfig.api} 
            page={page} 
            loadImportMap={() => import('.sitecore/import-map')} 
          > 
            {children} 
          </SitecoreProvider> 
        </ComponentPropsContext> 
      ); 
    }; 
    
    export default Providers; 
  7. The DesignLibrary component no longer receives an import map as a prop. Instead, it is provided by the SitecoreProvider component. For Content SDK apps based on Pages Router, the DesignLibrary component is present in src/Layout.tsx and must be updated:

    ... 
          <div className={mainClassPageEditing}> 
            {mode.isDesignLibrary ? ( 
              <DesignLibrary /> 
            ) : ( 
              <> 
                <header> 
                  <div id="header"> 
    .. 
  8. The renderEmptyPlaceholder method from the Placeholder class has been removed.

    import React from 'react'; 
    import { Placeholder } from '@sitecore-content-sdk/react'; 
    
    class MyCustomPlaceholder extends Placeholder { 
      render() { 
        ... 
        if (!placeholderRenderings.length) { 
          ... 
          return this.renderEmptyPlaceholder(emptyContent); 
        } 
        // Regular rendering logic 
        return super.render(); 
      } 
    } 

    If your implementation relies on that method for custom placeholders, you can use the renderEmptyPlaceholder helper method exported from react and nextjs packages.

    import React from 'react'; 
    import { PlaceholderComponent, renderEmptyPlaceholder } from '@sitecore-content-sdk/react'; 
    
    class Placeholder extends Placeholder { 
      render() { 
        ... 
        if (!placeholderRenderings.length) { 
          ... 
          return renderEmptyPlaceholder(emptyContent); 
        }
        // Regular rendering logic 
        return super.render(); 
      }
    } 
  9. By disabling React Suspense in placeholders, components render faster without the added Suspense overhead. However, if your app uses lazy-loaded components inside a <Placeholder> and expects a loading fallback to appear, you need to perform the following steps while upgrading:

    • Audit <Placeholder> usages where dynamic or lazy components are rendered.

    • Add disableSuspense={false} to any placeholder that depends on Suspense-based loading states.

Refactor components and interfaces

This section refactors all components, interfaces, and other files to match the new Content SDK app's structure.

To refactor your files:

  1. Copy the new component src/components/content-sdk/SitecoreStyles.tsx from your template app into the same folder in your existing JSS app.

  2. In Layout.tsx, import SitecoreStyles and place the component after Scripts, as shown in the following example:

    import SitecoreStyles from 'src/components/SitecoreStyles'; 
    ...  
        <Scripts /> 
        <SitecoreStyles layoutData={layoutData} /> 
    ...
  3. Throughout your JSS app, remove all usages of the publicUrl property of the now-obsolete config.

  4. Update references and imports for the following component, interfaces, higher-order components, and properties:

    Old

    New

    Type

    SitecoreContext

    SitecoreProvider

    component

    SitecoreContextProps

    SitecoreProviderProps

    interface

    SitecoreContextState

    SitecoreProviderState

    interface

    SitecoreContextReactContext

    SitecoreProviderReactContext

    interface

    WithSitecoreContextOptions

    WithSitecoreOptions

    interface

    WithSitecoreContextProps

    WithSitecoreProps

    interface

    WithSitecoreContextHocProps

    WithSitecoreHocProps

    interface

    useSitecoreContext()

    useSitecore()

    HOC

    withSitecoreContext()

    withSitecore()

    HOC

    context

    page

    property

    updateSitecoreContext

    updatePage

    property

    sitecoreContext

    page

    property

    Note

    The withSitecore higher-order component is deprecated. The recommended alternative is the useSitecore hook.

  5. Remove the SitecoreContext interface and update any references with the new Page interface from the SitecoreClient.

  6. Update references to the getServerSideProps and getStaticProps methods to getComponentServerProps without changing the existing method signature.

    If your component contains code that's executed based on static or server side Next.js context, import the isServerSidePropsContext helper method and implement it based on the following example:

    import { isServerSidePropsContext } from '@sitecore-content-sdk/nextjs/utils';  
    ...  
    export const getComponentServerProps: GetComponentServerProps = async (  
    rendering,  
    layoutData,  
    context  
    ) => {  
    if (isServerSidePropsContext(context)) {  
        // function implementation  
    }  
    };
  7. Update references and imports for the following services if you use them directly or substitute them by using the methods in the SitecoreClient class:

    Old

    New

    Type

    RestComponentLayoutService

    ComponentLayoutService

    service class

    RestComponentLayoutServiceConfig

    ComponentLayoutServiceConfig

    interface

    GraphQLEditingService

    EditingService

    service class

    GraphQLEditingServiceConfig

    EditingServiceConfig

    interface

    GraphQLDictionaryService

    DictionaryService

    service class

    GraphQLDictionaryServiceConfig

    DictionaryServiceConfig

    interface

    GraphQLLayoutService

    LayoutService

    service class

    GraphQLLayoutServiceConfig

    LayoutServiceConfig

    interface

    GraphQLPersonalizeService

    PersonalizeService

    service class

    GraphQLPersonalizeServiceConfig

    PersonalizeServiceConfig

    type

    GraphQLErrorPagesService

    ErrorPagesService

    service class

    GraphQLErrorPagesServiceConfig

    ErrorPagesServiceConfig

    interface

    GraphQLRedirectsService

    RedirectsService

    service class

    GraphQLRedirectsServiceConfig

    RedirectsServiceConfig

    type

    GraphQLRobotsService

    RobotsService

    service class

    GraphQLRobotsServiceConfig

    RobotsServiceConfig

    type

    GraphQLSiteInfoService

    SiteInfoService

    service class

    GraphQLSiteInfoServiceConfig

    SiteInfoServiceConfig

    type

    GraphQLSitemapXmlService

    SitemapXmlService

    service class

    GraphQLSitemapXmlServiceConfig

    SitemapXmlServiceConfig

    type

    GraphQLSitePathService

    SitePathService

    service class

    GraphQLSitePathServiceConfig

    SitePathServiceConfig

    interface

  8. Delete the DictionaryService interface and remove any references to it.

  9. Update the src/lib/component-props/index.ts file in your existing app using the one from your template app.

  10. Throughout your app, wherever is used, do the following:

    • Update imports of componentBuilder to use components instead, as shown in the following example:

      import components from '.sitecore/component-map';
    • Within <SitecoreProvider>, replace usages of the componentFactory prop to use components instead, as shown in the following example:

      <SitecoreProvider componentMap={components} ...>
  11. Update any remaining imports of temp/componentBuilder to use .sitecore/component-map instead.

  12. The @sitecore-content-sdk/content package has been decoupled from @sitecore-content-sdk/core to create a more focused "core" that can be referenced by other packages. The following changes are only required if you directly import from @sitecore-content-sdk/core.

    • The following submodules have been moved from @sitecore-content-sdk/core to @sitecore-content-sdk/content:

      Item

      Old path

      New path

      client

      @sitecore-content-sdk/core/client

      @sitecore-content-sdk/content/client

      codegen

      @sitecore-content-sdk/core/codegen

      @sitecore-content-sdk/content/codegen

      config-cli

      @sitecore-content-sdk/core/config-cli

      @sitecore-content-sdk/content/config-cli

      config

      @sitecore-content-sdk/core/config

      @sitecore-content-sdk/content/config

      editing

      @sitecore-content-sdk/core/editing

      @sitecore-content-sdk/content/editing

      i18n

      @sitecore-content-sdk/core/i18n

      @sitecore-content-sdk/content/i18n

      layout

      @sitecore-content-sdk/core/layout

      @sitecore-content-sdk/content/layout

      media

      @sitecore-content-sdk/core/media

      @sitecore-content-sdk/content/media

      personalize

      @sitecore-content-sdk/core/personalize

      @sitecore-content-sdk/content/personalize

      site

      @sitecore-content-sdk/core/site

      @sitecore-content-sdk/content/site

      Update all references to the old paths with the new ones.

    • All exports from the utils submodule are now available from the tools submodule. Update all references to the @sitecore-content-sdk/core/utils submodule and replace it with @sitecore-content-sdk/core/tools.

    • The following types and functions have been moved from @sitecore-content-sdk/core to @sitecore-content-sdk/content:

      Item

      Old path

      New path

      HTMLLink type

      @sitecore-content-sdk/core

      @sitecore-content-sdk/content

      StaticPath type

      @sitecore-content-sdk/core

      @sitecore-content-sdk/content

      defineConfig

      @sitecore-content-sdk/core

      @sitecore-content-sdk/content

      form

      @sitecore-content-sdk/core

      @sitecore-content-sdk/content

      Update all references to the old paths with the new ones.

    • The following tools have been moved from @sitecore-content-sdk/core/tools to @sitecore-content-sdk/content/tools:

      Item

      Old path

      New path

      generateSites

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      GenerateSitesConfig

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      GenerateMapFunction

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      GenerateMapArgs

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      extractFiles

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      writeImportMap

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      WriteImportMapArgs

      @sitecore-content-sdk/core/tools

      @sitecore-content-sdk/content/tools

      Update all references to the old paths with the new ones.

    • The following utilities and types have been removed from @sitecore-content-sdk/core/tools as they are no longer relevant or unused:

      Item

      Description

      generatePlugins

      No longer relevant

      PluginDefinition

      No longer relevant

      ModuleType

      No longer relevant

      tryParseEnvValue

      Unused utility

      isAbsoluteUrl

      Unused utility

Important

The default SXA rewrite logic has been changed to align with Next.js best practices for locale and to support the optional Shall language be preserved upon redirect? checkbox introduced in the Redirect Rules section in SitecoreAI. For example, earlier, when en is set as the default locale, URLs that do not specify a locale (like /my-page) resolves to that default locale. With this change, the same rule results in a redirect without the default locale if no locale is present. To continue using it as before, you must enable the Shall language be preserved upon redirect?.

Finalize build process and cleanup

This section contains changes related to the build process and finalizes the upgrade process.

To edit the build process and clean up your project:

  1. In your package.json file, do the following:

    • Remove the start:watch-components and bootstrap scripts and all mentions of these two scripts from the remaining scripts.

    • Remove the jss script.

    • Remove the install-pre-push-hook script.

    • Remove the scaffold script.

    • Update the build script with the following:

      "build": "cross-env NODE_ENV=production npm-run-all --serial sitecore-tools:generate-map sitecore-tools:build next:build",
    • Update the lint script by removing linting for the script folder:

      "lint": "eslint ./src/**/*.tsx ./src/**/*.ts",
    • (Optional) Add the following scripts, for dynamically generating the component map and building the Content SDK app:

      "sitecore-tools:generate-map": "sitecore-tools project component generate-map", 
      "sitecore-tools:generate-map:watch": "sitecore-tools project component generate-map --watch", 
      "sitecore-tools:build": "sitecore-tools project build",
    • Rename the start:connected script to dev and replace it with the following:

      "dev": "cross-env NODE_ENV=development npm-run-all --serial sitecore-tools:build --parallel next:dev sitecore-tools:generate-map:watch",
    • Rename the start:production to start and replace it with the following:

      "start": "cross-env-shell NODE_ENV=production npm-run-all --serial build next:start"
  2. Copy the sitecore.cli.config.ts file from your template app into your existing app.

    • Previously, all functions in the build array of the defineCliConfig options object accepted a scConfig property in their options object. This property is no longer required and is provided internally during build time. For example, the previous implementation for writeImportMap contained the scConfig property as shown:

      import scConfig from './sitecore.config'; 
      import { defineCliConfig } from '@sitecore-content-sdk/nextjs/config-cli'; 
      import { 
        ... 
        writeImportMap, 
      } from '@sitecore-content-sdk/nextjs/tools'; 
      
      export default defineCliConfig({ 
        config: scConfig, 
        build: { 
          commands: [ 
            ... 
            writeImportMap({ 
              scCofig: scConfig, 
              paths: ['src/components'], 
            }), 
          ], 
        }, 
        ... 
      }); 
    • The rest of the configuration remains the same after removing the property:

      import scConfig from './sitecore.config'; 
      import { defineCliConfig } from '@sitecore-content-sdk/nextjs/config-cli'; 
      import { 
        ... 
        writeImportMap, 
      } from '@sitecore-content-sdk/nextjs/tools'; 
      
      export default defineCliConfig({ 
        config: scConfig, 
        build: { 
          commands: [ 
            ... 
            writeImportMap({ 
              paths: ['src/components'], 
            }), 
          ], 
        }, 
        ... 
      }); 
  3. Because the build time artifacts metadata.json and sites.json (the second of which used to be called config.sites) are now created under the .sitecore temp folder at the root of the app, you need to update the imports of these artifacts accordingly throughout your application, making sure to rename instances of config.sites to sites.json.

  4. Content SDK introduces the sitecore-tools:build command that, similar to next:build, is used to generate build-time artifacts required for your app to function. Make sure this script is executed before you start your application.

  5. In your existing app's next.config.js file, make the following changes:

    • Migrate all Next config plugin logic (previously located in the src/lib/next-config folder) and all associated custom settings into the next.config.js file, then delete the now-redundant files from the lib folder.

    • Replace the existing defaultLocale property with the following:

      defaultLocale: process.env.DEFAULT_LANGUAGE || process.env.NEXT_PUBLIC_DEFAULT_LANGUAGE || 'en',
  6. Next.js 16 expects you to define allowable external image sources using remotePatterns instead of images.domains. Remove all entries of images.domains and set remotePatterns to allow Sitecore media URLs. Refer to the template app's next.config.js|ts file for more information.

  7. The Page type now includes a mode field of type PageMode, that provides runtime context (editing, preview, the Design Studio, etc). Update references to layout context properties like pageState, pageEditing, and renderingType with the new page.mode field as shown in the examples below:

    • If the rendering mode isDesignLibrary, find the following:

      if (layoutData.sitecore.context.renderingType === RenderingType.Component) { 
         ... 
      }

      Replace with:

      if (page.mode.isDesignLibrary) { 
         ... 
      }
    • If the rendering mode isNormal, find the following:

      if (layoutData.sitecore.context.pageState === LayoutServicePageState.Normal) { 
         ... 
      }

      Replace with:

      if (page.mode.isNormal) { 
         ... 
      }
    • Similarly, if the rendering mode isEditing or isPreview, update them to use the following:

      if (page.mode.isEditing || page.mode.isPreview) { 
        ... 
      }
  8. If you've customized your existing JSS app, refer to the obsolete JSS functionality section and make all changes necessary to refactor your code and then remove the obsolete parts of your app, such as:

    • Using appropriate data fetching functionality provided by scClient. Use your Sitecore Content SDK template app as a reference.

    • Replacing imports of SitecorePageProps to use "@sitecore-content-sdk/nextjs" instead of "lib/page-props". For example:

      import { SitecorePageProps } from "@sitecore-content-sdk/nextjs
Note

In their unaltered forms, the following files provided by the Next.js starter kit will need to be updated:

  • src/pages/api/robots.ts

  • src/pages/api/sitemap.ts

  • src/pages/[[...path]].tsx

  • src/pages/404.tsx

  • src/pages/500.tsx

  • src/Bootstrap.tsx

  • src/_app.tsx

Obsolete and revised functionality in your existing app

Some parts of existing JSS apps are either revised or no longer required in Content SDK apps, meaning they can be removed. However, if your app contains custom code that uses any of this obsolete functionality, or if you have any customizations in the affected files or folders, you will need to modify your app accordingly.

After you've finished refactoring, you can remove any obsolete parts to reduce the overall size of your app:

  • The scripts/config folder, which contains the plugins that JSS used to generate the runtime config under the src/temp folder. All of this has been replaced by sitecore.config.ts, and a config file is no longer generated at build time.

  • The scripts/scaffold-component folder, which contains the script for the jss scaffold component command. This is now replaced by a new CLI command sitecore-tools scaffold.

  • The scripts/templates folder, which contains the templates JSS used for scaffolding components. This is now replaced by the new CLI configuration sitecore.cli.config.ts.

  • The scripts/generate-config.ts script that generated the runtime config file. This is now replaced by sitecore.config.ts.

  • The scripts/generate-metadata.ts script that generated the metadata.json required for editing integration. This is now replaced by the generateMetadata() function in sitecore.cli.config.ts which is executed by the new CLI command sitecore-tools build.

  • The scripts/generate-component-builder script, which generated the component builder that manages registration of components. This is now replaced by component-map.

  • The scripts/generate-plugins.ts script is no longer required.

  • The scripts/bootstrap.ts script that handled running build-time scripts. This is now replaced by the CLI and sitecore.cli.config.ts.

  • The scripts/utils.ts file that stores utilities for scripts is no longer used.

  • If you've already disabled graphQL code generation for your JSS app, the /scripts folder and the tsconfig.scripts.json file are no longer needed.

  • The src/lib/page-props-factory plugins that created contextual SitecorePageProps objects. This is now replaced by the functions of SitecoreClient.

  • src/lib/site-resolver, which is now replaced by scClient.resolveSite().

  • src/lib/extract-path, which must now be imported from @sitecore-content-sdk/nextjs/utils.

  • src/lib/sitemap-fetcher, which is now replaced scClient.getSiteMap().

  • src/lib/middleware. All proxy (previously called middleware) is now defined in proxy.ts and executed using the defineProxy utility function.

  • src/lib/next-config. All Next.js config settings are now consolidated in nextj.config.js.

  • The src/lib/config.ts type, which defined runtime config, is now replaced by sitecore.config.ts. The following services are now incorporated into SitecoreClient. If your solution includes customization of any of these services, you need to extend SitecoreClient and override any services that need to be extended:

    • src/lib/graphql-client-factory

    • src/lib/dictionary-service-factory.ts

    • src/lib/layout-service-factory.ts

    • src/lib/graphql-editing-service.ts

  • The src/lib/page-props.ts type that defined SitecorePageProps has been moved to the base @sitecore-content-sdk/nextjs package, and must now be imported from there instead.

Removal of Experience Editor

Unlike JSS for SitecoreAI, Content SDK doesn't support the Experience Editor tool and, for that reason, doesn't include the chromes-based integration required by Experience Editor. Instead, all visual editing with Content SDK is done with the SitecoreAI page builder using metadata integration.

Important

When migrating to Content SDK, Content Editor Preview is not supported. Content SDK removes all Experience Editor–based rendering and preview capabilities, including preview functionality accessed from the Content Editor. Preview and editing are supported only through Page Builder.

The following packages have been updated for Content SDK in relation to removal of Experience Editor support. Familiarize yourself with the updates and note any breaking changes this might introduce to your application so you can address them during the upgrade process:

sitecore-jss

  • Now present under sitecore-content-sdk/core package.

  • Removed the HtmlElementRendering interface, meaning only ComponentRendering interface is now used.

  • field.editable is no longer available. Instead, field.metadata is used for edit mode.

  • Removed the EditMode.Chromes enum value.

  • LayoutServiceContext no longer exposes editMode.

  • Renamed the HorizonEditor utility class to PagesEditor.

  • Removed the ExperienceEditor utility class.

  • Removed the handleEditorAnchors utility.

  • Removed all EditFrame utilities, including:

    • DefaultEditFrameButton

    • DefaultEditFrameButtons

    • DefaultEditFrameButtonIds

    • EditFrameDataSource

    • ChromeCommand

    • FieldEditButton

    • WebEditButton

    • EditButtonTypes

    • mapButtonToCommand

sitecore-jss-react

  • Now present under the react package.

  • Removed Chromes mode support.

  • Removed the HtmlElementRendering interface.

  • Removed the EditFrameProps interface and the EditFrame component.

  • Updated PlaceholderCommon.getPlaceholderDataFromRenderingData to accept isEditing (boolean) instead of editMode:

    getPlaceholderDataFromRenderingData(rendering: ComponentRendering | RouteData, name: string, isEditing: boolean)
  • All field components now reference field.metadata instead of field.editable.

sitecore-jss-nextjs

  • Now present under sitecore-content-sdk/nextjs.

  • Removed Chromes mode support.

  • Removed the getPublicUrl function.

  • Removed the EditFrame component.

  • Removed the HtmlElementRendering interface.

  • Removed the following services and middlewares:

    • EditingDataCache, EditingDataDiskCache, and EditingData.

    • EditingDataMiddleware and EditingDataMiddlewareConfig.

    • EditingDataService.

    • ServerlessEditingDataService and ServerlessEditingDataServiceConfig.

    • VercelEditingDataCache.

    • The editingDataService instance.

  • EditingConfigMiddleware no longer accepts config.pagesEditMode.

  • All field components now reference field.metadata instead of field.editable.

templates/next.js

  • Edit mode updates:

    • Removed exact checks for EditMode.Metadata.

    • Removed the editing data API router api/editing/data/[key].ts.

  • General configuration updates:

    • Removed config.publicUrl usage.

    • Removed the PUBLIC_URL environment variable.

    • Removed the nextConfig.assetPrefix setting.

    • Removed the nextConfig.env.PUBLIC_URL environment variable.

    • Removed Next.js rewrites for the following:

      • Sitecore API Endpoints: /sitecore/api/:path*

      • Media items: /-/:path*

      • Sitecore service pages: /sitecore/service/:path*

Next steps

To finalize the upgrade process, make sure you resolve any errors and warnings you encounter. Enable debug logging for Content SDK specific issues to assist you if necessary.

If you have suggestions for improving this article, let us know!