Sitecore JSS Apps to SitecoreAI Content SDK

written by Steve Sobenko

|

May 2026

Sitecore XM Cloud has come a long way. When we were building the first sites on Sitecore XM Cloud, my first thought was there's no way this is "no more upgrades". Sure, huge benifits of the new flagship Sitecore being SaaS, cloud hosted, rolling updates, frequent updates. It definitely took the pain out of the platform side upgrades. On the JSS library side, I could see it coming. I made some friendly side bets "You'll someday see Sitecore XM Cloud 2.0". I figured it was inevitable. Well, close. XM Cloud became SitecoreAI, that was just a name change. But JSS is being wholesale replaced by ContentSDK. The 2 products, XM Cloud on JSS in 2022 and SitecoreAI on ContentSDK today are a world of improvement. I may have gotten my naming wrong, but my hunch was right. The upgrade was inevitable. Nothing to sweat, it's not like the old XP upgrades. 

What We're Learning Migrating Our Clients' JSS Apps to SitecoreAI Content SDK 2.x

For the past few months, our Sitecore team at Nishtech has been moving our clients' Next.js applications off the Sitecore JavaScript Services SDK (JSS) and onto SitecoreAI Content SDK 2.1. We wanted to document what the work actually looks like. What changes, what gets simpler, and what to watch out for if your team is thinking about the same move.

This Unfortunately Isn't Optional

Before going further, the deadline matters. Sitecore has formally deprecated JSS for SitecoreAI, and the support timeline is short. If you're running JSS on SitecoreAI, you have to be off it by the end of June 2026. Here's the lifecycle in plain terms:

  • JSS SDK 21.X reached end of life in March 2025. No support.
  • JSS SDK 22.X is in maintenance until June 2026. After that, end of life.
  • Content SDK 1.X is in maintenance into early 2027.
  • Content SDK 2.X is the active, fully supported version. New features, dependency updates, bug fixes, and security patches all land here.

For teams who've been watching the JSS roadmap. JSS 23.X is expected around May or June of 2026, but it will only support the traditional DXP products like XM and XP. It will not support SitecoreAI. There is no future JSS path for SitecoreAI implementations. Content SDK is it.

That changes the things for anyone still on JSS 22.X. This isn't a "we'll get to it next year" upgrade. It's a hard deadline. Our clients who started planning early are in much better shape than the ones treating it as a future problem.

Why Our Clients Are Making the Move

Content SDK is what Sitecore wants you running on SitecoreAI. JSS still works, but it's carrying years of tooling and generated code that the new SDK doesn't need. Our clients are upgrading for a few reasons:

  • They're tired of maintaining JSS code that the platform no longer asks for.
  • They want to run on React 19 and Next.js 16.
  • They're moving to the SitecoreAI Page Builder, which replaces Experience Editor and only works with metadata-based integration. Experience Editor is also depreciated for SitecoreAI. Sad news for all the Agency Accelerators built in the past few years built on Experience Editor.
  • They want analytics, events, and personalization baked into the SDK instead of bolted on through a separate Cloud SDK.

After the migration, the repo is smaller. We're usually seeing 30 to 40 percent less code once all the obsolete folders, scripts, and dependencies come out.

A Quick Word on "Accelerators"

Many of the projects landing on our desks were originally built on top of (other) partner-supplied "accelerators." Frameworks, component libraries, and starter kits that were sold as a head start on JSS implementations. In practice, several of these accelerators are now the single biggest source of debt in the migration. They wrapped JSS APIs, extended its plugins, and baked assumptions about middleware, data fetching, and Experience Editor deep into the code. With JSS going away, all of that wrapping has to come out before the actual upgrade work can start.

It's a fair thing to ask. If an accelerator can't survive a major version upgrade of the platform it was built on, how much did it really accelerate? The clients of ours getting through this migration cleanest are the ones who stayed close to the standard JSS starter kit. The ones with a custom partner locked accelerator layer are paying for it twice. Once when it was built, and again now as it's pulled apart.

We're not against shared tooling. We build internal utilities for our clients all the time. But there's a difference between a thin layer of helpers and a framework on top of a framework. The first survives a platform shift. The second usually doesn't.

What Actually Changes During the Migration

Here's a walkthrough of the work our engineers are doing on these projects.

Dependency Updates

The package list gets cleaned out. We pull the old @sitecore-jss/* and @sitecore-cloudsdk/* packages along with the whole GraphQL code generation toolchain (graphql-let, @graphql-codegen/*, and friends). In their place:

"@sitecore-content-sdk/nextjs": "^2.0.0",
"@sitecore-content-sdk/cli": "^2.0.0",
"@sitecore-content-sdk/analytics-core": "^2.0.0",
"@sitecore-content-sdk/personalize": "^2.0.0",
"@sitecore-content-sdk/events": "^2.0.0",
"next": "^16.1.1",
"react": "^19.1.0",
"react-dom": "^19.1.0"

One thing that's bitten us. TypeScript, the ESLint plugins, and @types/node all have to move to specific versions for the new packages to compile. We've had a couple of false starts on projects where these were left where they were.

Environment Variables Get Renamed

Easy to underestimate this step. Most variables need new names, and a bunch of them move to the NEXT_PUBLIC_ prefix so they're available on the client:

  • SITECORE_API_KEY becomes NEXT_PUBLIC_SITECORE_API_KEY
  • SITECORE_API_HOST becomes NEXT_PUBLIC_SITECORE_API_HOST
  • SITECORE_SITE_NAME becomes NEXT_PUBLIC_DEFAULT_SITE_NAME
  • DEFAULT_LANGUAGE becomes NEXT_PUBLIC_DEFAULT_LANGUAGE
  • JSS_EDITING_SECRET becomes SITECORE_EDITING_SECRET
  • SITECORE_EDGE_URL becomes NEXT_PUBLIC_SITECORE_EDGE_PLATFORM_HOSTNAME

One that got us twice. DISABLE_SSG_FETCH is renamed to GENERATE_STATIC_PATHS, and the meaning is flipped. Do a find and replace without flipping the boolean and static path generation breaks silently. It's on our pre-flight checklist now.

Data Fetching Consolidates Into SitecoreClient

Dev teams like this one. JSS apps used to wire up a bunch of separate services: GraphQLLayoutService, GraphQLDictionaryService, RestComponentLayoutService, GraphQLPersonalizeService, and so on. Content SDK puts all of that into one SitecoreClient class. Where our clients have customizations in any of these services, we extend SitecoreClient and override what needs overriding.

The new pattern in pages and error routes is cleaner too:

import scConfig from 'sitecore.config';

const page = client.getPage(...);

<SitecoreContext
  api={scConfig.api}
  page={page}
>
  {children}
</SitecoreContext>

Middleware Becomes "Proxy"

Next.js 16 renamed middleware to "proxy" to better match what it actually does at the edge. Content SDK follows suit and gives you a defineProxy utility that replaces the old plugin-based middleware setup. Most of our clients' apps end up with something like this in src/proxy.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: [...] };

Order matters. App Router projects run the chain as locale, then multisite, then redirects, then personalize. Pages Router skips locale: multisite, redirects, personalize. We added this to the runbook because the symptoms of an out-of-order chain are subtle and easy to miss.

Analytics and Events Move In-House

The standalone Cloud SDK is gone. Tracking, events, and personalization live inside Content SDK now. The old CloudSDK(...).addEvents().initialize() setup gets replaced with:

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(),
  ],
});

For our clients running personalization in production, we treat this step as its own validation phase. Confirm the events fire, the cookies set the way you'd expect, and audiences resolve correctly before moving on.

React 19 Component Refactors

Content SDK 2.1 is built around React 19 patterns, so a bunch of the JSS habits have to be rewritten. The ones that come up on every project:

  • SitecoreContext becomes SitecoreProvider
  • useSitecoreContext() becomes useSitecore()
  • withSitecoreContext() becomes withSitecore(), which is itself deprecated in favor of the hook
  • updatePage becomes setPage
  • sitecoreContext.context.page becomes page
  • Built-in components that used React.forwardRef now treat ref as a regular prop

The withPlaceholder HOC changes shape the most. The old version named each placeholder as a prop. The new one hands you a placeholders map:

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);

Page Mode Replaces Layout Context Properties

The Page type now has a mode field that tells you what the runtime context is. Editing, preview, design library, normal. All the legacy pageState, pageEditing, and renderingType checks have to be rewritten:

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

// New
if (page.mode.isNormal) { ... }

// Editing / preview check
if (page.mode.isEditing || page.mode.isPreview) { ... }

Build Scripts Get Simpler

A lot of the old npm scripts go away. start:watch-components, bootstrap, jss, scaffold, install-pre-push-hook, and the graphql:update chain all come out. What's left is much cleaner:

"build": "cross-env NODE_ENV=production npm-run-all --serial sitecore-tools:generate-map sitecore-tools:build next:build",
"dev": "cross-env NODE_ENV=development npm-run-all --serial sitecore-tools:build --parallel next:dev sitecore-tools:generate-map:watch",
"start": "cross-env-shell NODE_ENV=production npm-run-all --serial build next:start"

The new sitecore.cli.config.ts file picks up what used to live in scattered scripts under /scripts. Once the migration is done, the whole scripts/ folder and tsconfig.scripts.json usually get deleted.

Forms and SXA Components

For our clients using Sitecore forms, the existing BYOC wrappers have to be updated through Content Editor. That means opening each form, swapping the BYOC Wrapper control for the Forms component, and moving the formId parameter into its new field. We do this content work alongside the code so editors don't lose any form behavior in the cutover.

The SXA add-on also ships updated versions of Image.tsx, Promo.tsx, Title.tsx, and several SASS files. Where our clients customized these in JSS, we replicate those customizations on top of the new versions rather than overwriting them blindly.

Experience Editor Goes Away

Content SDK doesn't support Experience Editor or Content Editor Preview. All visual editing happens in the SitecoreAI Page Builder using metadata integration. For our clients still working in Experience Editor day to day, this is a change management conversation as much as a technical one. We loop in content teams well before the cutover so authors aren't surprised the morning of.

Effective January 1, 2027, Experience Editor will be officially deprecated and Page builder will be the supported editing experience in SitecoreAI

Things We've Learned to Watch For

A few things that keep coming up across migrations:

  • The edgeUrl change is easy to miss. If you've explicitly set edgeUrl in sitecore.config, it has to pull from NEXT_PUBLIC_SITECORE_EDGE_PLATFORM_HOSTNAME for Next.js builds. Otherwise the client bundle won't have it.
  • SXA's default rewrite logic changed. URLs without a locale used to resolve to the default locale. Now they redirect without the default locale unless "Shall language be preserved upon redirect?" is enabled on the redirect rule. We audit redirect rules on every project.
  • Build artifacts moved. metadata.json and sites.json (formerly config.sites) now live under the .sitecore temp folder. Any code that imports these needs the path updated.
  • Suspense is off by default in placeholders. If you have lazy-loaded components that depend on Suspense fallbacks, you have to set disableSuspense={false} on those placeholders explicitly.

Where We Are Today

Content SDK is a real upgrade over JSS for SitecoreAI work. The codebase comes out smaller, React and Next.js are current, personalization is built in, and Page Builder is a better editing experience than what came before. The migration itself isn't trivial, but it's well-defined, and the maintenance savings are showing up clearly in the projects we've finished.

With JSS 22.X maintenance ending in June 2026, there's not a lot of runway. If you're on JSS 22.0 and haven't started planning the move, the official Sitecore upgrade guide is the right place to start. And if you want to compare notes on any specific part of the upgrade, our Sitecore team is always happy to talk.

Headshot of Steve Sobenko

Steve Sobenko

Steve is a seasoned technology professional with over 20 years of experience leading cross-functional teams and delivering enterprise web solutions. With expertise in front-end and back-end development, cloud computing, security, and analytics, he’s been at the forefront of digital transformation since the early days of the web. Steve is passionate about helping clients achieve their business goals through innovative, scalable technology solutions.

X
Cookies help us improve your website experience.
By using our website, you agree to our use of cookies.
Confirm