---
title: "Upgrade JSS 22.0 Next.js apps to Content SDK 2.1"
slug: "upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1"
abstract: "How to upgrade your JSS 22.0 Next.js apps to Content SDK 2.1."
---
# Upgrade JSS 22.0 Next.js apps to Content SDK 2.1

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

> [!note]
> **XM Cloud is now SitecoreAI**
> Some code examples, images, and UI labels may still use XM Cloud while engineering assets are being updated.

> [!note]
> **Before you begin**
> -   If you haven't already done so, [upgrade your app to JSS 22.0.0](https://doc.sitecore.com/sai/en/developers/jss/22/jss-sai/upgrade-jss-21-7-next-js-apps-to-version-22-0-0.html).
>
> -   We recommend you read the official release notes for [React 19](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) and [Next.js 16](https://nextjs.org/docs/app/guides/upgrading/version-15) to understand what has changed in these new versions.
>
> -   Familiarize yourself with the [JSS](https://github.com/Sitecore/jss/blob/dev/CHANGELOG.md) and [Content SDK](https://github.com/Sitecore/content-sdk/blob/dev/CHANGELOG.md) 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:

:::walkthrough
1. [What's new in Content SDK?](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#whats-new-in-content-sdk)
2. [Update application dependencies through all versions](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#update-application-dependencies-through-all-versions)
3. [Create a Content SDK 2.1 application](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#create-a-content-sdk-21-application)
4. [Update the SXA add-on](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#update-the-sxa-add-on)
5. [Disable automatic GraphQL code generation](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#disable-automatic-graphql-code-generation)
6. [Update existing forms to use the new wrapper](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#update-existing-forms-to-use-the-new-wrapper)
7. [Migrate to Content SDK architecture](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#migrate-to-content-sdk-architecture)
8. [Obsolete and revised functionality in your existing app](https://doc.sitecore.com/sai/en/developers/content-sdk/20/upgrade-jss-22-0-next-js-apps-to-content-sdk-2-1.html#obsolete-and-revised-functionality-in-your-existing-app)
:::

## 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](https://doc.sitecore.com/sai/en/developers/content-sdk/20/update-eslint-to-version-9.html).
    - Update `typescript` to version `~5.4.0`.
    - Install `sharp@0.32.6` for improved memory usage using the following command:

        ```shell
        npm i sharp@0.32.6
        ```

    - Update React and Next.js:

        ```json
        "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:

    ```shell
    npm install
    ```

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

    ```csharp
    "@typescript-eslint/no-unused-vars": [
      "error",
      {
        "caughtErrorsIgnorePattern": "."
      }
    ],
    ```

4. Make the following changes to `tsconfig.json`:
    - Add above the `lib` entry:

        ```json
        ...
        "types": ["node"],
        ...
        ```

    - Delete the following from `compilerOptions.paths`:

        ```json
        "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:

    ```shell
    npx create-content-sdk-app@2.1.0 nextjs
    ```

2. If prompted to install the `create-content-sdk-app@2.1.0` 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](https://github.com/Sitecore/xmcloud-starter-js/tree/main). 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:`

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

        ```scss
        ...
          >.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:

    ```text
    "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`:

```ts
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:

        ```ts
        import config from 'temp/config'
        ```

    - Replace these with the following:

        ```text
        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:

    ```ts
    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:

    <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Old (JSS)</p></th><th class="th"><p>New (Content SDK)</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">SITECORE_API_KEY</code></p></td><td class="td"><p><code class="code">NEXT_PUBLIC_SITECORE_API_KEY</code></p></td></tr><tr><td class="td"><p><code class="code">SITECORE_API_HOST</code></p></td><td class="td"><p><code class="code">NEXT_PUBLIC_SITECORE_API_HOST</code></p></td></tr><tr><td class="td"><p><code class="code">SITECORE_SITE_NAME</code></p></td><td class="td"><p><code class="code">NEXT_PUBLIC_DEFAULT_SITE_NAME</code></p></td></tr><tr><td class="td"><p><code class="code">DEFAULT_LANGUAGE</code></p></td><td class="td"><p><code class="code">NEXT_PUBLIC_DEFAULT_LANGUAGE</code></p></td></tr><tr><td class="td"><p><code class="code">JSS_EDITING_SECRET</code></p></td><td class="td"><p><code class="code">SITECORE_EDITING_SECRET</code></p></td></tr></tbody></table>

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:

    ```ts
    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:

        ```ts
        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.

    <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Item</p></th><th class="th"><p>Description</p></th></tr></thead><tbody><tr><td class="td"><p>For sitemap and robots.txt</p></td><td class="td"><p>Use <code class="code">SitemapMiddleware</code> or <code class="code">RobotsMiddleware</code> from <code class="code">@sitecore-content-sdk/nextjs/middleware</code></p></td></tr><tr><td class="td"><p>Editing APIs</p></td><td class="td"><p>Use <code class="code">EditingConfigMiddleware</code>, <code class="code">EditingRenderMiddleware</code>, or <code class="code">FEAASRenderMiddleware</code> from <code class="code">@sitecore-content-sdk/nextjs/editing</code></p></td></tr><tr><td class="td"><p>Healthcheck</p></td><td class="td"><p>Use the <code class="code">HealthcheckMiddleware</code> from <code class="code">@sitecore-content-sdk/nextjs/monitoring</code></p></td></tr></tbody></table>

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:

        ```ts
        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:

        ```ts
        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:

        ```ts
        import { CloudSDK } from '@sitecore-cloudsdk/core/browser';
        import { SitecorePageProps } from '@sitecore-content-sdk/nextjs';
        import '@sitecore-cloudsdk/events/browser';
        ```

    - Add the following imports:

        ```ts
        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:

        ```ts
        import { pageView } from '@sitecore-cloudsdk/events/browser';
        ```

    - Replace it with the following:

        ```ts
        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:

        ```ts
        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:

        ```ts
        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:

        ```csharp
        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:
        >
        > ```javascript
        > 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:

        ```ts
        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:

        ```ts
        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:

    ```ts
    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:

    ```ts
    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

        ```ts
        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:

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

        Can be streamlined using `passThroughComponentProps` as shown:

        ```ts
        <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](https://react.dev/reference/react/forwardRef) best practices.

    > [!important]
    > Please refer to the official [React 19 upgrade guide](https://react.dev/blog/2024/04/25/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:

    ```ts
    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:

    ```ts
    ...
          <div className={mainClassPageEditing}>
            {mode.isDesignLibrary ? (
              <DesignLibrary />
            ) : (
              <>
                <header>
                  <div id="header">
    ..
    ```

8. The `renderEmptyPlaceholder` method from the `Placeholder` class has been removed.

    ```ts
    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.

    ```ts
    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:

    ```ts
    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:

    <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Old</p></th><th class="th"><p>New</p></th><th class="th"><p>Type</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">SitecoreContext</code></p></td><td class="td"><p><code class="code">SitecoreProvider</code></p></td><td class="td"><p>component</p></td></tr><tr><td class="td"><p><code class="code">SitecoreContextProps</code></p></td><td class="td"><p><code class="code">SitecoreProviderProps</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">SitecoreContextState</code></p></td><td class="td"><p><code class="code">SitecoreProviderState</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">SitecoreContextReactContext</code></p></td><td class="td"><p><code class="code">SitecoreProviderReactContext</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">WithSitecoreContextOptions</code></p></td><td class="td"><p><code class="code">WithSitecoreOptions</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">WithSitecoreContextProps</code></p></td><td class="td"><p><code class="code">WithSitecoreProps</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">WithSitecoreContextHocProps</code></p></td><td class="td"><p><code class="code">WithSitecoreHocProps</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">useSitecoreContext()</code></p></td><td class="td"><p><code class="code">useSitecore()</code></p></td><td class="td"><p>HOC</p></td></tr><tr><td class="td"><p><code class="code">withSitecoreContext()</code></p></td><td class="td"><p><code class="code">withSitecore()</code></p></td><td class="td"><p>HOC</p></td></tr><tr><td class="td"><p><code class="code">context</code></p></td><td class="td"><p><code class="code">page</code></p></td><td class="td"><p>property</p></td></tr><tr><td class="td"><p><code class="code">updateSitecoreContext</code></p></td><td class="td"><p><code class="code">updatePage</code></p></td><td class="td"><p>property</p></td></tr><tr><td class="td"><p><code class="code">sitecoreContext</code></p></td><td class="td"><p><code class="code">page</code></p></td><td class="td"><p>property</p></td></tr></tbody></table>

    > [!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:

    ```ts
    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:

    <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Old</p></th><th class="th"><p>New</p></th><th class="th"><p>Type</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">RestComponentLayoutService</code></p></td><td class="td"><p><code class="code">ComponentLayoutService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">RestComponentLayoutServiceConfig</code></p></td><td class="td"><p><code class="code">ComponentLayoutServiceConfig</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">GraphQLEditingService</code></p></td><td class="td"><p><code class="code">EditingService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLEditingServiceConfig</code></p></td><td class="td"><p><code class="code">EditingServiceConfig</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">GraphQLDictionaryService</code></p></td><td class="td"><p><code class="code">DictionaryService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLDictionaryServiceConfig</code></p></td><td class="td"><p><code class="code">DictionaryServiceConfig</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">GraphQLLayoutService</code></p></td><td class="td"><p><code class="code">LayoutService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLLayoutServiceConfig</code></p></td><td class="td"><p><code class="code">LayoutServiceConfig</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">GraphQLPersonalizeService</code></p></td><td class="td"><p><code class="code">PersonalizeService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLPersonalizeServiceConfig</code></p></td><td class="td"><p><code class="code">PersonalizeServiceConfig</code></p></td><td class="td"><p>type</p></td></tr><tr><td class="td"><p><code class="code">GraphQLErrorPagesService</code></p></td><td class="td"><p><code class="code">ErrorPagesService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLErrorPagesServiceConfig</code></p></td><td class="td"><p><code class="code">ErrorPagesServiceConfig</code></p></td><td class="td"><p>interface</p></td></tr><tr><td class="td"><p><code class="code">GraphQLRedirectsService</code></p></td><td class="td"><p><code class="code">RedirectsService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLRedirectsServiceConfig</code></p></td><td class="td"><p><code class="code">RedirectsServiceConfig</code></p></td><td class="td"><p>type</p></td></tr><tr><td class="td"><p><code class="code">GraphQLRobotsService</code></p></td><td class="td"><p><code class="code">RobotsService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLRobotsServiceConfig</code></p></td><td class="td"><p><code class="code">RobotsServiceConfig</code></p></td><td class="td"><p>type</p></td></tr><tr><td class="td"><p><code class="code">GraphQLSiteInfoService</code></p></td><td class="td"><p><code class="code">SiteInfoService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLSiteInfoServiceConfig</code></p></td><td class="td"><p><code class="code">SiteInfoServiceConfig</code></p></td><td class="td"><p>type</p></td></tr><tr><td class="td"><p><code class="code">GraphQLSitemapXmlService</code></p></td><td class="td"><p><code class="code">SitemapXmlService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLSitemapXmlServiceConfig</code></p></td><td class="td"><p><code class="code">SitemapXmlServiceConfig</code></p></td><td class="td"><p>type</p></td></tr><tr><td class="td"><p><code class="code">GraphQLSitePathService</code></p></td><td class="td"><p><code class="code">SitePathService</code></p></td><td class="td"><p>service class</p></td></tr><tr><td class="td"><p><code class="code">GraphQLSitePathServiceConfig</code></p></td><td class="td"><p><code class="code">SitePathServiceConfig</code></p></td><td class="td"><p>interface</p></td></tr></tbody></table>

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:

        ```text
        import components from '.sitecore/component-map';
        ```

    - Within `<SitecoreProvider>`, replace usages of the `componentFactory` prop to use `components` instead, as shown in the following example:

        ```text
        <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`:

        <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Item</p></th><th class="th"><p>Old path</p></th><th class="th"><p>New path</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">client</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/client</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/client</code></p></td></tr><tr><td class="td"><p><code class="code">codegen</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/codegen</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/codegen</code></p></td></tr><tr><td class="td"><p><code class="code">config-cli</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/config-cli</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/config-cli</code></p></td></tr><tr><td class="td"><p><code class="code">config</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/config</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/config</code></p></td></tr><tr><td class="td"><p><code class="code">editing</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/editing</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/editing</code></p></td></tr><tr><td class="td"><p><code class="code">i18n</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/i18n</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/i18n</code></p></td></tr><tr><td class="td"><p><code class="code">layout</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/layout</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/layout</code></p></td></tr><tr><td class="td"><p><code class="code">media</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/media</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/media</code></p></td></tr><tr><td class="td"><p><code class="code">personalize</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/personalize</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/personalize</code></p></td></tr><tr><td class="td"><p><code class="code">site</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/site</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/site</code></p></td></tr></tbody></table>

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

        <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Item</p></th><th class="th"><p>Old path</p></th><th class="th"><p>New path</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">HTMLLink</code> type</p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content</code></p></td></tr><tr><td class="td"><p><code class="code">StaticPath</code> type</p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content</code></p></td></tr><tr><td class="td"><p><code class="code">defineConfig</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content</code></p></td></tr><tr><td class="td"><p><code class="code">form</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content</code></p></td></tr></tbody></table>

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

        <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Item</p></th><th class="th"><p>Old path</p></th><th class="th"><p>New path</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">generateSites</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr><tr><td class="td"><p><code class="code">GenerateSitesConfig</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr><tr><td class="td"><p><code class="code">GenerateMapFunction</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr><tr><td class="td"><p><code class="code">GenerateMapArgs</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr><tr><td class="td"><p><code class="code">extractFiles</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr><tr><td class="td"><p><code class="code">writeImportMap</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr><tr><td class="td"><p><code class="code">WriteImportMapArgs</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/core/tools</code></p></td><td class="td"><p><code class="code">@sitecore-content-sdk/content/tools</code></p></td></tr></tbody></table>

        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:

        <table style="width:100%;" class="informaltable frame-void rules-rows"><thead><tr><th class="th"><p>Item</p></th><th class="th"><p>Description</p></th></tr></thead><tbody><tr><td class="td"><p><code class="code">generatePlugins</code></p></td><td class="td"><p>No longer relevant</p></td></tr><tr><td class="td"><p><code class="code">PluginDefinition</code></p></td><td class="td"><p>No longer relevant</p></td></tr><tr><td class="td"><p><code class="code">ModuleType</code></p></td><td class="td"><p>No longer relevant</p></td></tr><tr><td class="td"><p><code class="code">tryParseEnvValue</code></p></td><td class="td"><p>Unused utility</p></td></tr><tr><td class="td"><p><code class="code">isAbsoluteUrl</code></p></td><td class="td"><p>Unused utility</p></td></tr></tbody></table>

> [!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:

        ```json
        "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:

        ```text
        "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:

        ```text
        "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:

        ```text
        "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:

        ```ts
        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:

        ```ts
        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:

        ```js
        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:

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

        Replace with:

        ```ts
        if (page.mode.isDesignLibrary) {
           ...
        }
        ```

    - If the rendering mode `isNormal`, find the following:

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

        Replace with:

        ```ts
        if (page.mode.isNormal) {
           ...
        }
        ```

    - Similarly, if the rendering mode `isEditing` or `isPreview`, update them to use the following:

        ```ts
        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:

        ```ts
        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](https://doc.sitecore.com/sai/en/developers/jss/22/jss-sai/upgrade-jss-22-6-next-js-apps-to-version-22-7.html#UUID-8bf810d0-bf43-99db-baef-bd636958c593_section-idm1853500309652518) 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:

::::tabs
:::tab{title="sitecore-jss"}
{ .notintoc }

- 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`

:::
:::tab{title="sitecore-jss-react"}
{ .notintoc }

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

    ```ts
    getPlaceholderDataFromRenderingData(rendering: ComponentRendering | RouteData, name: string, isEditing: boolean)
    ```

- All field components now reference `field.metadata` instead of `field.editable`.

:::
:::tab{title="sitecore-jss-nextjs"}
{ .notintoc }

- 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`.

:::
:::tab{title="templates/next.js"}
{ .notintoc }

- 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](https://doc.sitecore.com/sai/en/developers/content-sdk/20/debug-logging-in-content-sdk-apps.html "Debug logging in Content SDK apps") specific issues to assist you if necessary.

> [!note]
> **Web experiences and experiments**
> If you use Sitecore Personalize web experiences or experiments, after upgrading to Content SDK, start or restart a single experience or experiment (or start a dummy one) in order to republish it and regenerate the `cloud-version.min.js` library. For instructions, see [Start an experience in Sitecore Personalize](https://doc.sitecore.com/personalize/en/users/sitecore-personalize/introduction-to-experiences/managing-experience-status-in-sitecore-personalize/start-an-experience-in-sitecore-personalize.html), or [Start an experiment in Sitecore Personalize](https://doc.sitecore.com/personalize/en/users/sitecore-personalize/introduction-to-experiments-in-sitecore-personalize/managing-experiment-status-in-sitecore-personalize/start-an-experiment-in-sitecore-personalize.html). [Pausing experiments](https://doc.sitecore.com/personalize/en/users/sitecore-personalize/introduction-to-experiments-in-sitecore-personalize/managing-experiment-status-in-sitecore-personalize/pause-an-experiment-in-sitecore-personalize.html) and [experiences](https://doc.sitecore.com/personalize/en/users/sitecore-personalize/introduction-to-experiences/managing-experience-status-in-sitecore-personalize/pause-an-experience-in-sitecore-personalize.html) and restarting them can invalidate test results.