Experience Sitecore ! | All posts tagged 'XM Cloud'

Experience Sitecore !

More than 300 articles about the best DXP by Martin Miles

Sitecore PowerShell as a SitecoreAI Marketplace app

I have reverse-engineered the Sitecore PowerShell Extension and reassembled it into a SitecoreAI Marketplace app!

This PoC is essentially a blueprint app. On its own, it is a universally working example. Still, its real benefit comes from this app providing a ready-to-use boilerplate that can be reused to build a variety of specialized SitecoreAI Marketplace apps on top of the SPE approach.

The most awesome feature is that all of your Marketplace context values could be easily passed into a remotely executed PowerShell script as a script parameter: there is a convenient Script Parameters mapping with maramater token preview (so that you never miss the right value!)

Here's what it looks like:

To enable SPE with Remoting:

  1. From SitecoreAI Deploy, add SPE_REMOTING_SECRET environmental CM secret, then re-deploy.
  2. Install a package, which will enable SPE with Remoting: SPE_with_Remoting.zip (3.93 kb)
  3. This package also adds a disabled sitecore\speremoting user with admin rights, which you must enable manually from User Manager

Once this setup is complete, the environment is fully prepared to use the app. The Marketplace app supports multitenancy; however, SPE Remoting must be enabled individually for every environment you intend to work with.


Top 10 Mistakes Organizations Make on Sitecore XM Cloud Implementations

Sitecore XM Cloud represents a monumental shift in how we build and deliver digital experiences. The promise of a fully managed, composable DXP is incredibly compelling, and for good reason. However, after seeing numerous projects in the wild and talking with fellow developers and architects, I've noticed a pattern of common, time-consuming, and often costly mistakes. These aren't the simple "RTFM" errors; they are the insidious problems that stem from underestimating the fundamental paradigm shift from traditional Sitecore XP to a headless, SaaS world.

I've spent the last couple of years deep in the trenches of XM Cloud, and I've seen what works and what causes projects to grind to a halt. In this post, I’m going to walk you through the top 10 mistakes I see organizations making time and time again. My goal is to save you the headaches, the late nights, and the budget overruns. Let's take a look at them.

1. Migrating Information Architecture Without Restructuring First

This is, without a doubt, the single biggest mistake I see teams make, and it poisons the well for the entire project. It seems logical to start by moving your content, but on XM Cloud, that's a recipe for disaster. Failing to address Information Architecture first is the source of all the further downstream chaos.

In the world of Sitecore XP, we had a lot of flexibility. You could have mixed templates in content folders, no clear separation between page structure and data items, and site definitions buried deep in the content tree. XM Cloud, on the other hand, is ruthless in its demand for a clean, predictable structure. It expects a strict hierarchy: Tenant → Site → Content.

Why It Becomes a Nightmare

When you try to push a legacy XP content tree into XM Cloud, the entire system starts to break in subtle and frustrating ways:

  • Serialization Fails: The dotnet sitecore ser push command will throw errors about non-unique paths or other inconsistencies that were perfectly valid in your old instance.
  • Component Bindings Break: Pages might render, but components won't bind to their datasources correctly because the expected folder structures don't exist.
  • Pages Editor is Unusable: Content authors will complain about missing fields, broken placeholders, and a generally unusable editing experience.
I cannot stress this enough: before you migrate a single piece of content, you must first migrate your IA. This means creating a clean, XM Cloud-native IA in your new project, and then mapping your old content to that new structure. It feels like extra work upfront, but it will save you weeks of painful debugging down the line.

2. Ignoring Experience Edge Rate Limits and Caching Architecture

Once you get past the initial IA migration, the next major pitfall I see is a fundamental misunderstanding of Experience Edge. We get so excited about the idea of a globally replicated, high-performance content delivery network that we forget it operates under specific rules and limitations. As I covered in one of my own posts, you absolutely must know these limitations before you start building.

Experience Edge is not a magic black box. It has hard limits that can and will break your application in production if you don't design for them from day one. Here are the critical ones:

Limit Type

Constraint
Impact of Ignoring
API Rate Limit
80 requests/second
HTTP 429 errors, service unavailability
GraphQL Query Results
1,000 items per query
Incomplete data requires pagination
GraphQL Query Complexity
~250 (undocumented)
Queries fail with complexity errors
Default Cache TTL
4 hours
Stale content for up to 4 hours

The Architectural Imperative: Cache Everything

The 80 requests/second limit seems generous, but it's a cap on uncached requests. A single user visiting a server-side rendered (SSR) page with multiple components could generate a dozen or more GraphQL queries. In a high-traffic scenario, you will hit that limit almost instantly. This is why Sitecore's guidance, and my own experience, dictate that you must architect your solution with a cache-first mindset. This means leveraging Static Site Generation (SSG) and Incremental Static Regeneration (ISR) wherever possible.

Trying to retrofit a caching strategy onto a chatty, SSR-heavy application after it's already built is a nightmare. You must plan your component rendering strategies from the beginning. Ask yourself for every component: - "Can this be statically rendered? Does it need to be server-side rendered? Can we use client-side fetching for dynamic elements?". Ignoring these questions is a direct path to production performance issues and emergency redesigns.

3. Underestimating Non-SXA to Headless SXA Migration Complexity

This is a big one, and it often comes as a nasty surprise to teams migrating from older, non-SXA Sitecore XP instances. The assumption is that you can just lift your existing components and content structure and somehow make them work in a headless fashion. The reality is that XM Cloud expects Headless SXA as its baseline. If your legacy solution isn't built on SXA, you are not performing a simple migration; you are performing a complete architectural rebuild.
I've seen teams budget for a straightforward content migration only to discover that their entire presentation layer is fundamentally incompatible. Migrating from a non-SXA site can add an extra month or two to a project easily, depending on the complexity.

Why It's a Rebuild, Not a Migration

Headless SXA enforces a strict, convention-based approach to site structure and presentation that simply doesn't exist in non-SXA builds. Here’s what you’re actually signing up for:

  • Rebuilding Structure: You must manually recreate your site architecture using SXA conventions (Tenant → Site → Page Branches → Data).
  • Rebuilding Layouts: All of your existing layouts must be rebuilt as Page Designs.
  • Rebuilding Shared Components: Headers, footers, and other shared elements must be recreated as Partial Designs.
  • Converting All Renderings: Every single one of your renderings must be converted into a Headless SXA-compatible JSS component.
  • Remapping Placeholders: Your old custom placeholders won't work as-is. The placeholder mapping in XM Cloud is far more rigid and requires a complete overhaul.
Failing to account for this massive effort is one of the fastest ways to blow your budget and timeline. If you are coming from a non-SXA background, you must treat the project as a replatforming exercise, not a simple upgrade.

4. Assuming MVC Backend Customizations Can Be Migrated Directly

For years, the power of Sitecore development lay in its extensible backend. We built custom renderField pipelines, hooked into countless processors, and used dependency injection to create powerful, server-side logic. In XM Cloud, that world is gone. I’ve seen teams spend weeks trying to figure out how to migrate their complex backend code, only to realize that it’s a futile effort. If your old solution contains backend customization, you must find a way to implement it in the head application.

This is a fundamental paradigm shift that many seasoned Sitecore developers struggle with. XM Cloud is a headless-first platform, which means your .NET code is running in a black box, completely decoupled from the rendering host. There is no way to directly influence the rendered output from the backend.

The Headless Mindset Shift

Here’s what this means in practice:

  • renderField Pipelines are Obsolete: Any logic that modifies field rendering at request time must be moved to your Next.js components.
  • Controller Logic Must Be Refactored: Your MVC controller actions that process data or modify component output must be re-implemented as stateless services or APIs that your Next.js application can call.
  • Dependency Injection is Different: Your custom services and logic can't be injected into rendering pipelines anymore. A great alternative I've seen work well is using PageProps factory plugins in the Next.js application to fetch and inject data into your components.
Trying to shoehorn your old MVC patterns into XM Cloud will lead to nothing but frustration. You have to embrace the headless mindset and move your logic to where it now belongs: the head application.

5. Not Understanding Next.js Routing and Configuration Fragility

One of the most common cries for help I see on community channels is, - "I just set up my project, and every page is a 404!". This is almost always the result of underestimating the sheer fragility of the Next.js routing and configuration setup in an XM Cloud project. There is a big number of moving parts that all have to work correctly to get pages to display.

This isn't a single point of failure; it's a dozen small, interconnected dependencies that can break the entire application. It’s a classic “needle in a haystack” problem that can burn hours, if not days, of a developer's time.

The House of Cards: Common Failure Points

If you're hitting routing issues, here’s a checklist of the most likely culprits I've seen:

  • The [[...path]].tsx file: This is the heart of Sitecore's catch-all routing. If this file is accidentally renamed, if a merge conflict corrupts it, or if the special bracket characters are wrong, all your Sitecore-managed routes will fail.
  • Site Name Mismatches: The siteName in your .env files must perfectly match the site name configured in Sitecore under /sitecore/content/MyTenant/MySite/Settings/Site Grouping/MySite. A tiny typo will break everything.
  • Environment Variable Loading: Remember that Next.js loads environment files in a specific order (scjssconfig.json.env.env.local). A misconfigured variable in one file can silently override the correct value in another.
  • Layout Service Failures: The [[...path]].tsx file relies on a successful response from the Layout Service. If your API key is wrong, your JSS Editing Secret doesn't match, or the rendering host items at /sitecore/system/Settings/Services/Rendering Hosts are misconfigured, the Layout Service will fail, and your app will render a 404.
  • Special Folder Names: Next.js has special folder names like pages and app. If a git merge accidentally creates an empty folder with one of these names in your rendering host's file system, it can confuse the Next.js router into thinking no routes exist.
Troubleshooting this requires a methodical approach. You have to check every single one of these connection points, from your local environment files all the way to your CM instance configuration. There are no shortcuts.

6. Overlooking Serialization Duplicate Item Issues

Serialization is the backbone of modern Sitecore development, but it has its own set of quirks that can bring a project to a standstill. One of the most frustrating issues I’ve seen is the "Non-unique paths cannot be serialized" error. This problem, as detailed by Brad Fettes, is both familiar and maddeningly tedious to resolve.

This error typically occurs when you have two items with the same name under the same parent item. While Sitecore’s database is perfectly happy with this (since it uses GUIDs for identity), the file system is not. When the serialization process tries to create two YAML files with the exact same name in the same directory, it fails. The most common culprit? Duplicate __Standard Values items.

How the Trap is Set

This usually happens when developers are working in parallel on different environments. Here’s a typical scenario:

  1. Developer A creates a new template and its standard values on their local machine and serializes them.
  2. Before Developer A commits and pushes their changes, Developer B creates the same template and standard values on a shared development environment.
  3. Developer A pushes their code. Now, the serialized YAML for the standard values exists in the repository.
  4. When you try to pull these changes and push them to the shared environment, the serialization engine sees a conflict: the GUID from the YAML file is different from the GUID of the item that already exists in the Sitecore database, even though the path is identical. The result: Non-unique paths cannot be serialized.

The Painful Manual Fix

The error message suggests renaming the item, but that’s not an option for __Standard Values. The only way to fix this is a manual, repetitive process:

  1. Copy the second GUID from the error message.
  2. Paste it into the search bar in the Content Editor of the target environment to find the offending item.
  3. Manually delete the duplicate item.
  4. Re-run the dotnet sitecore ser push command.
  5. Repeat the process if you get another error for a different item.
This is a huge time sink, and it highlights the fragility of a file-based serialization strategy when multiple developers are making content changes. It’s a stark reminder that in the XM Cloud world, a disciplined Git workflow and clear communication about who is creating which items are more critical than ever.

7. Trusting Undocumented Platform Behavior

One of the hardest lessons to learn when moving to a SaaS platform like XM Cloud is that you are no longer in control of the underlying infrastructure. Things can and will change without notice. A painful example of this surfaced in mid-2024, when deployments across numerous projects began failing due to mysterious compilation errors: an unannounced, breaking change in how the XM Cloud build process consumed the xmcloud.build.json file.

For months, the build process had seemingly ignored the buildTargets property, defaulting to using the solution (.sln) file. Then, one day, Sitecore deployed a change that strictly enforced this property. Teams that had (logically) pointed this to their specific project (.csproj) file suddenly found their deployments failing because the new build process couldn't restore NuGet packages correctly. The error messages about missing assemblies were completely misleading, sending developers on a wild goose chase for a problem that wasn't in their code.

The Sobering Reality of SaaS

This incident is a perfect illustration of a new class of problems we face with XM Cloud:

  • Undocumented Breaking Changes: The platform is constantly evolving, and not every change is going to be announced in advance. What worked yesterday might be broken today for reasons entirely outside your control.
  • Misleading Error Messages: The errors you see are often symptoms of a deeper platform issue, not a problem with your own code, which makes troubleshooting incredibly difficult.
  • Reliance on Support: The only way this issue was diagnosed was through a Sitecore support ticket. You must be prepared to engage with support and provide detailed logs to resolve these kinds of problems.
My advice: when a previously working process suddenly breaks for no apparent reason, and your local builds are fine, your first suspect should be an unannounced platform change. Document your troubleshooting steps meticulously and open a support ticket sooner rather than later. Don't waste days debugging your own code when the platform itself may have shifted under your feet.

8. Neglecting Local Development Environment Complexity

One of the great promises of XM Cloud was a simplified local development setup. While it has improved in many ways, I’ve found that many teams underestimate the complexity and fragility of the Docker-based environment. It is far from a "plug and play" experience and is a significant source of friction, especially for developers new to the project or to Docker itself.

The official Sitecore documentation provides a good starting point for troubleshooting, but it also reveals just how many things can go wrong. These aren't edge cases; they are common, everyday problems that can cost your team hours of productivity.

The Daily Hurdles of Local Development

Here are some of the recurring issues that turn local setup into a constant battle:

  • The down.ps1 Ritual: If you shut down your machine without running the down.ps1 script, your containers are left in an exited state. The next time you run up.ps1, it will fail. You have to remember to run the cleanup script every single time. It’s a small thing, but it’s a constant papercut.
  • Corporate Network and Firewall Policies: This is a huge one. I’ve seen countless hours lost because a company's security policies block communication between containers or prevent access to the Docker DNS. The solutions often involve switching to hyperv isolation or getting firewall rules changed, which can be a bureaucratic nightmare.
  • DNS Configuration: Sometimes the CM container will fail to authorize on startup due to invalid DNS settings. The fix is to manually set the DNS in your Docker Desktop settings to a public one like 8.8.8.8, but this is not documented in the standard setup guides and is something you only discover after hours of frustration.
  • The "Unhealthy" Container: Seeing your cm container in an "unhealthy" state is a rite of passage for XM Cloud developers. Debugging it requires you to manually check the Docker logs, exec into the container, and curl the health check endpoint to figure out what went wrong. It’s a tedious and opaque process.
Don't treat the local development environment as a given. You need to budget time for setup, troubleshooting, and creating internal documentation for your specific network environment. A smooth local setup is not a luxury; it's a prerequisite for a productive team.

The good news is that since the introduction of Metadata Editing Mode in 2025, developers can progress with an FE-first approach, which allows scaffolding a front-end app and developing it against the remote XM Cloud environment, avoiding all the hassles of dealing with local Windows-based containers.

9. Missing SXA Feature Parity Gaps

For teams that have been using SXA on-premise for years, there’s a natural assumption that the features they rely on will be available in XM Cloud. This assumption is often wrong and can lead to significant unplanned development work. I’ve seen this myself on projects where clients were extensive users of features like Snippets, Scriban, Content Tokens, or Overlays, only to discover during migration that these features simply don’t exist in the current version of Headless SXA.

This leaves development teams with a difficult choice: either abandon the functionality or rebuild it from scratch in a headless world.

Rebuilding What Was Once Out-of-the-Box

This isn’t a trivial task. Take Content Tokens, for example. To replicate this functionality, you can’t just write a simple helper function. A proper implementation requires:

  1. A Custom GraphQL Query: You need to create a GraphQL query to fetch the token data, similar to how the Dictionary Service works.
  2. A Custom Service: You need a service that fetches this data and, crucially, caches it in memory to avoid hammering the Experience Edge API on every page load, especially during a static build.
  3. Integration with PageProps: This service must be integrated into the PageProps factory plugin to make the token data available to all your components.
This is a significant amount of work to replicate a feature that was once a standard part of SXA. It’s a classic example of the “rebuild, don’t migrate” reality of XM Cloud. You must perform a thorough audit of all SXA features your existing solution uses and verify their availability in XM Cloud before committing to a migration plan. Don’t assume feature parity.

10. Failing to Plan for Workflow and Multilingual Migration Complexity

Finally, I want to touch on two areas that are often treated as afterthoughts but are fraught with hidden complexity: workflows and multilingual content. These are the silent killers of a migration project. The issues don’t show up as significant, loud deployment errors; they manifest as confusing problems for content authors long after the initial migration is supposedly “done.”

Because you no longer have direct database access, you can’t just run a SQL script to fix things when they go wrong. You are entirely at the mercy of your serialization and import tools.

The Silent Failures

Here’s what often goes wrong:

  • Workflows Break Silently: During content import, items can be created without their original workflow state, or XM Cloud might reject an invalid workflow ID from your old instance. The result is that editors can’t publish migrated content, and nobody knows why until they try. Auto-trigger actions also frequently fail due to missing commands. The only solution is to manually map and reassign workflows to thousands of items after the import, a tedious and error-prone task.
  • Multilingual Content Gets Corrupted: Migrating multilingual sites is exponentially more complex. I’ve seen shared fields get overwritten by an import from a different language, layout variations between languages get lost, and media items have inconsistent versioning. These are incredibly difficult problems to untangle without direct database access.
These issues highlight the need for meticulous planning and, most importantly, rigorous verification. A migration isn’t successful when the import script finishes. It’s successful when you have clean verification reports, and your content authors have confirmed that they can edit, publish, and see their content correctly in all languages.

Conclusion

The move to Sitecore XM Cloud is an exciting and necessary evolution for the platform. However, it is not a simple upgrade. It is a fundamental paradigm shift that requires a new way of thinking about architecture, development, and deployment. The biggest mistakes I’ve seen are not the result of bad code, but of bad assumptions - assuming that what worked in the on-premise world will work in a composable, SaaS world.

My advice is to approach your first XM Cloud project with a healthy dose of humility. Assume nothing. Question everything. Budget time for learning, for troubleshooting, and for the inevitable “unknown unknowns.” The platform is powerful, but it demands respect for its complexity.

I hope this list helps you avoid some of the pitfalls I’ve seen. If you’re struggling with your XM Cloud implementation or planning a migration, I’m always happy to share my experiences. Feel free to drop me a message!

Resolving broken images issue on XM Cloud starterkit running in local containers

A guide on how to resolve the media problem with the default vanilla StarterKit (foundation head) when images do not show on a site when accessed by a hostname.

Reproducing the problem

  1. Pull the latest starter kit, run init.ps1 , and up.ps1 as normal. Everything is fresh and clean; nothing else than that.
  2. When CM spins up, create a site collection followed by a site with the default name (nextjs-starter) matching the name of the JSS app.
  3. Open the home page in Experience Editor and drop an Image component to that page, upload and choose the image, save, and confirm it looks fine in EE.
  4. Open the home page again on the site: https://nextjs.xmc-starter-js.localhost and see the error

The error

Invalid src prop (https://cm/-/jssmedia/Project/Tenant/Habitat/LA.jpg?h=408&iar=0&w=612&ttc=63890432287&tt=4BBE52A4592C2DBCAE59361096C0E4D3&hash=0CA75E384F533EE5539236785DCF0E22) on `next/image`, hostname "cm" is not configured under images in your `next.config.js`

What happens?

The hostname of a local CM container is applied to the generated media URL (https://cm). That is not right, as CM hostname is not accessible outside of containers, and only works within the internal Docker network at the HTTP protocol, not HTTPS. After playing with the image URL, it was clear it works by a relative path, trimming the hostname from the start. Both URLs below are valid and show the image:

Testing an assumption

I thought if there was a problem on the datasource resolver of the Image component, but the resolver wasn't set. Just for the sake of experiment, decided to explicitly set image component to use `/sitecore/system/Modules/Layout Service/Rendering Contents Resolvers/Datasource Resolver`, since it has the same effect as when not set, along with unchecking Include Server URL in Media URLs settings for that resolver.

And on the resolver, unchecking as below:

That effectively resolved the issue. My guess was valid, so let's now seek a permanent solution.

The working solution

Once the assumption of removing a hostname is proven, let's take it out at the CM level so that it universally applies to your environments and you don't need to precisely set resolvers on each individual component. The below config patch does exactly what we need.

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <layoutService>
      <configurations>
        <config name="sxa-jss">
          <rendering>
            <renderingContentsResolver>
              <!-- Set the desired values for the JSS configuration -->
              <IncludeServerUrlInMediaUrls>false</IncludeServerUrlInMediaUrls>
            </renderingContentsResolver>
          </rendering>
        </config>
      </configurations>
    </layoutService>
  </sitecore>
</configuration>

That resolved my problem: the desired image loaded well.

Hope this helps you as well!

Changing item ID in XM Cloud from item's context menu

Historically, changing the ID of an item in Sitecore was widely believed to be impossible, particularly within the constraints of XM Cloud.

In the XP era, I experimented with a custom package nearly a decade ago that did successfully change item IDs. However, achieving this required considerable effort: decompiling out-of-the-box DLLs, reverse engineering the code, and then rebuilding DLLs to match various Sitecore versions and dependencies. The process was complex and not ideal, dependent on runtime specifics. I managed to make it function, but lots have changed since then.

With XM Cloud, many of those challenges have been eliminated. Notably, the platform now includes Sitecore PowerShell Extensions (SPE) out of the box. This makes it feasible to develop a universal script that can change the ID of any item in the content tree, invoked directly from the context menu without the need for server-level modifications. All it takes is a simple package containing a single Sitecore item.

Why change ID?

1. Database Merges and Migrations

  • Resolving ID Conflicts During Database Merges: When combining multiple Sitecore databases (e.g., from separate instances or acquisitions), duplicate IDs can occur if items were created independently. Changing the ID of conflicting items in one database allows seamless integration without data loss.
  • Content Migration from Legacy Systems: During upgrades or migrations from older Sitecore versions or other CMS platforms, imported items might have IDs that clash with existing ones. Changing IDs ensures uniqueness while preserving content structure.
  • Multi-Environment Synchronization: If dev, staging, and production environments diverge (e.g., due to unsynced TDS/Unicorn serializations), changing IDs in one environment can align them without recreating everything.
  • Cross-Database Item Transfers: When moving items between master, core, or web databases, ID collisions might arise; changing the ID facilitates clean transfers.

2. Integration with External Systems

  • Aligning with External Data Feeds or APIs: If an external system (e.g., a CRM like Salesforce or a data warehouse) references Sitecore items by GUIDs but uses its own fixed IDs, changing Sitecore's item ID to match the external one ensures synchronization without modifying the external system.
  • Third-Party Tool Compatibility: Some integrations (e.g., e-commerce plugins or analytics tools) might require specific ID formats or mappings; changing IDs bridges mismatches.
  • Bi-Directional Sync with Other Platforms: In setups with real-time syncing (e.g., via Sitecore Data Exchange Framework), ID changes might be needed to resolve sync errors caused by GUID mismatches.
  • Federated Identity Management: For systems integrating Sitecore with identity providers, where user-generated content items need ID alignment for security or tracking.

3. Item Recovery and Error Correction

  • Recovering from Accidental Deletions: If a critical item is deleted (and not sent to the Recycle Bin) but referenced extensively, recreating it with a new ID and updating links/indexes can restore functionality faster than manual fixes, especially if the original ID causes reference breakage.
  • Fixing Overwritten or Forgotten Items in Version Control: In team environments using TDS or Unicorn, if an item is overwritten or omitted during serialization, changing its ID can resolve conflicts and reintegrate it without rebuilding the entire project.
  • Correcting Database Corruption or Duplicates: Rare DB errors (e.g., from failed restores) might create duplicate IDs; changing one item's ID eliminates the duplication.
  • Repairing Broken References After Errors: If an item's ID leads to index or link database issues (e.g., due to partial publishes), changing it and triggering a reference update can fix widespread breakage.

4. Development and Testing Scenarios

  • Simulating ID Conflicts in Testing: Developers might change IDs to test merge scripts, index rebuilds, or reference update pipelines in controlled environments.
  • Refactoring Large Content Trees: During site redesigns, changing IDs of template items or folders can help reorganize without disrupting live content, especially if combined with link repairs.
  • Debugging Custom Modules: To isolate issues in custom code that relies on specific IDs (e.g., caching or workflows), temporarily changing an ID can aid troubleshooting.
  • Performance Optimization Testing: Changing IDs to force index refreshes or cache invalidations in load testing, helping identify bottlenecks.

4. Other creative scenarios

  • Proof of authoring: In certain cases, you may want to intentionally leave a trace or proof of authoring in the item's ID so that you can prove the fact that you've done this job at some stage later. Once working on a questionable project, I used this trick to encode my phonу number as the last digits of the site definition item. This does not affect any functionality, but at the same time cannot be just a random coincidence.
  • Easter eggs: In some mostly non-production cases, you may want to have some fun with issuing creative naming IDs. HEX-based codes allow plenty of creativity there. For example, all these are valid HEX numbers: 
    • Four chars long: BEEF, CAFE, BABE, FACE, CODE, FEED, etc.
    • Eight chars long: DEADFACE, C0FFEEED, C0DEC0DE, BEEFC0DE, etc.
    • Twelve char long: DEADC0FFEEED, DEADFADEBEEF, AD1DA5AD1DA5, etc.

 

Key Features of the PowerShell Module

The PowerShell module provided below delivers the following capabilities:

  • Assigns a new ID to any item: Accepts user input for the new ID, supporting not only standard content items but also templates, media, system items, and more.

  • Processes hierarchical structures: Handles items with children, fields, and sections, while maintaining the integrity of Standard Values for templates.

  • Updates derived content items: Sets the correct TemplateID on all derived items, preventing "object reference not set" errors.

  • Moves and patches descendants: Migrates and updates all child sections and fields under the new template as needed.

  • Refreshes all references: Updates any base templates, field sources, or XML fields that reference the old template.

  • Cache management: Flushes Sitecore caches and, optionally, rebuilds the Link Database and triggers a publish.

  • Efficient querying: Utilizes fast queries to ensure every relevant content item is included.

  • Comprehensive edge case handling: Covers all major scenarios and exceptions.

How It Works

Since Sitecore does not provide an API for changing item IDs directly, the script implements a robust workaround:

  1. Duplicate the source item (with all fields) under a new ID using the SPE API, which supports custom ID assignment.

  2. Move all children from the old item to the newly created item.

  3. Update all references in the database to point from the old ID to the new one.

  4. Delete the original item once all dependencies have been switched.

Note: Due to the item deletion step involved, this script cannot be used on items that originate from resource files; only items stored in a database are eligible.

Usage

Download

[Download package: ChangeItemID-1.0.zip]

Dictionary in XM Cloud

Localization is more than translation - it's about delivering a seamless, culturally relevant experience for every visitor. In Sitecore XM Cloud, dictionary items provide a simple, robust way to centralize UI text and labels for all languages, directly accessible in your Next.js frontend. Below, I’ll walk through the practical setup, usage patterns, and expert recommendations based on Sitecore’s official documentation and proven community practices.

What Are Dictionary Items?

Dictionary items in XM Cloud let you store and manage all your UI phrases centrally.
Instead of hardcoding "Read More", "Submit",  or error messages, you create dictionary keys under your site’s /Dictionary item. Each key holds localized values for every language you support.

Why:
  • Centralized: Update once, used everywhere
  • Multi-language: Add a new language, all keys covered
  • Consistent: No more stray hardcoded strings

When to Use Dictionary vs. Fields

Typically, you would use dictionary entries for generic text reused in many places (e.g., button labels like "Submit", form field placeholders, system messages). For content that might be specific to a single page or component (e.g., a marketing tagline, section heading, or lengthy description), consider making it a field in a content item or datasource rather than a shared dictionary entry. This gives content authors more flexibility to customize text in context. 

A hybrid approach can work too, for example, use a dictionary phrase as a fallback but allow an override via a field in the CMS if the editor wants a custom message in one place.

How Dictionary Items Work in XM Cloud

In XM Cloud, dictionary items are stored at: /sitecore/content/{collection}/{site}/Dictionary and is fetched via GraphQL through the Layout/Dictionary service. Essentially, for each page request, a GraphQL query runs to get all dictionary entries under the site’s dictionary path for the given language. The Next.js SDK’s DictionaryServiceFactory handles this, so you typically don’t need to write this query yourself. If curious, the query filters by the dictionary root item path, language, and the Dictionary Entry template, and returns all key-phrase pairs. Because this data is pulled at request-time (or build-time for static pages), the translations are ready by the time React components render. No client-side extra fetch is needed for dictionary data. It’s included in the page HTML/props payload.

Each dictionary item represents a key (e.g., "read"), and under it, each language version holds the translated phrase.

For multi-site or SXA setups, you can create a shared dictionary (often in a Shared site or at the tenant root), and then set up a fallback so multiple sites reuse the same dictionary keys. On the integration side, XM Cloud provides a Dictionary Service API, available via REST or GraphQL, which populates the dictionary data at build or runtime for your Next.js app.

Sitecore’s Next.js SDK (part of Headless JSS) comes pre-configured to utilize dictionary data for localization. Here’s how the pieces fit together:

  • Next.js Internationalization (i18n) Settings. In your Next.js app’s next.config.js, define the locales your site supports and a default locale. These locales should match the languages enabled in Sitecore. For example:
    i18n: {
      locales: ['en', 'fr-CA', 'es'], 
      defaultLocale: 'en'
    }
    This allows Next.js to handle locale-specific routes, such as /fr-ca/page-name for French Canadian. The defaultLocale should correspond to your site’s default language, often pulled from a config setting of package.json in the Sitecore starters. If you add a new language to Sitecore, update this config and redeploy the app so Next.js knows about the new locale.
  • Page Props and Dictionary Data. The Sitecore Next.js SDK fetches dictionary entries for each page request (or build) and injects them into the page properties. Specifically, the JSS Page Props Factory (a plugin in the Next.js sample app) uses the Dictionary Service to retrieve all dictionary phrases for the current site/language, and includes them as a dictionary object in pageProps. This happens server-side, either at build time for static generation or on the server for SSR, so that the dictionary is ready by the time the React components render.
  • I18n Provider. The Next.js app uses the next-localization library (a lightweight i18n solution) to provide translations. In the app’s custom _app.tsx, an <I18nProvider> is configured to wrap the page component, initialized with the locale and the dictionary data from Sitecore. For example:
    // In _app.tsx
    import { I18nProvider } from 'next-localization';
    function App({ Component, pageProps }) {
      const { dictionary, locale, ...rest } = pageProps;
      return (
        <I18nProvider lngDict={dictionary} locale={locale}>
          <Component {...rest} />
        </I18nProvider>
      );
    }
    Here, pageProps.dictionary contains all key–phrase pairs for the current locale, and pageProps.locale is the language code. The I18nProvider makes a translation function available to all components via React context.
  • Using the Translation Hook. Inside your React components, you use the useI18n() hook (from next-localization) to access the localization context. See the below paragraph for the exact dictionary consumption code sample.

The Single useTranslation Hook Pattern (with Fallback Defaults)

To keep things tidy, many teams prefer a single useTranslations hook. Here’s a pattern that ensures you never show a blank label, even if the dictionary entry is missing, by supplying a fallback default:

import { useI18n } from 'next-localization';

export function useTranslation() {
  const i18n = useI18n();
  // Utility: always show a fallback if dictionary value is missing
  const getTranslation = (key, fallback) => i18n?.t(key) || fallback;

  return {
    readLabel: getTranslation('read', 'Read'),
    submitLabel: getTranslation('submit', 'Submit'),
    // Add more keys as needed
  };
}

// Usage in a component
const translations = useTranslation();

return (
  <div>
    <button>{translations.readLabel}</button>
  </div>
);

Why this is better:

  • No undefined or blank UI if a dictionary key is missing
  • All translations accessible via one hook - simple, scalable
  • Easy to add more keys as your UI grows

Using Shared SXA Dictionaries & Fallback Domains

If you’re using SXA or multiple sites, you can set up a shared dictionary and configure fallback so every site can leverage the same keys.

Setup Steps:

  1. Create a Shared Dictionary. Place it in a shared location, such as /sitecore/content/{collection}/Shared/Dictionary
  2. Set Dictionary Domain. In Sitecore, under your site’s Dictionary item, set the Dictionary Domain field to the shared dictionary’s path. (Official Doc)
  3. Configure Fallback. On your site’s dictionary, enable "fallback domain" to point to the shared dictionary.

In your Next.js app, the Dictionary Service will automatically merge keys from both the site and shared domains. 

Storybook: Mocking Dictionaries for Isolated UI Development

When using Storybook, components expecting dictionary values may break outside the app context. To avoid this, you can mock the next-localization context in .storybook/preview.tsx:

import { I18nProvider } from 'next-localization';

const mockDictionary = {
  read: 'Read',
  submit: 'Submit',
  // Add other keys as needed
};

export const decorators = [
  (Story) => (
    <I18nProvider lngDict={mockDictionary} locale="en">
      <Story />
    </I18nProvider>
  ),
];
Why this matters:
  • Ensures all components render correctly in isolation
  • Lets designers and QA see accurate UI text in stories
  • Helps catch missing dictionary keys before production

Troubleshooting Dictionary Issues

If you encounter an issue where dictionary translations are not appearing in the Next.js app, it is highly likely that it happens because of one of the very frequently missed things. Consider the following checks:
  • Verify Config and App Name. Make sure the Next.js app’s configured site name (app name) matches the Sitecore site name. This is typically set in your app’s package.json (config.appName) or .env and used by the JSS config. If it mismatches Sitecore’s expected name, the dictionary service might look in the wrong place. In XM Cloud projects, the app name is usually the same as your site name in Sitecore.
  • Check Dictionary Domain Path. As noted, ensure the site’s dictionary domain/path settings in Sitecore are correct. If the Dictionary item was renamed or moved, update the site settings or the config patch so the head application knows where to fetch phrases.
  • Publish Content. Confirm that the dictionary items are published to the target environment (Edge). In a development scenario, if using Connected Mode, ensure the dictionary items exist in the expected database. After editing dictionary entries in the Pages or Content Editor interface, run a publish. Unpublished items will not appear in the GraphQL results.
  • For preview mode issues, rebuild the search index. On XM Cloud, indexes are auto-rebuilt on deploy, but if you import items or restore content, an index rebuild might be necessary.
  • Ensure a valid site root is defined. If you see errors like “Valid value for rootItemId not provided” in logs or GraphQL responses, it indicates the dictionary GraphQL service couldn’t auto-resolve the site’s root. Ensure your site template is correct; if fixing it, you can remove any hardcoded rootItemId overrides you may have added during debugging.

Bonus: Dictionary Migration and Conversion SPE Script

The below script copies dictionary items from an old XP database (referred to as old) to the master database of the locally-run XM Cloud environment and also converts Dictionary entries from a custom format of the Habitat website (which many folks have used as a starter kit, regardless) to the XM Cloud format, which is hard-defined by a dictionary template coming from the items resource file:
param(
    [string]$SourceDatabase = "old",
    [string]$SourcePath = "/sitecore/content/Habitat/Global/Dictionary",
    [string]$TargetDatabase = "master",
    [string]$TargetPath = "/sitecore/content/Zont/Habitat/Dictionary"
)

$srcFolderTemplate = "{98E4BDC6-9B43-4EB2-BAA3-D4303C35852E}"
$srcEntryTemplate = "{EC4DD3F2-590D-404B-9189-2A12679749CC}"
$srcPhraseField = "{DDACDD55-5B08-405F-9E58-04F09AED640A}"

$trgFolderTemplate = "{267D9AC7-5D85-4E9D-AF89-99AB296CC218}"
$trgEntryTemplate = "{6D1CD897-1936-4A3A-A511-289A94C2A7B1}"
$trgKeyField = "{580C75A8-C01A-4580-83CB-987776CEB3AF}"
$trgPhraseField = "{2BA3454A-9A9C-4CDF-A9F8-107FD484EB6E}"

function Copy-DictionaryItemsRecursive {
    param(
        [Sitecore.Data.Items.Item]$SrcParent,
        [Sitecore.Data.Items.Item]$TrgParent,
        [Sitecore.Data.Database]$SrcDB,
        [Sitecore.Data.Database]$TrgDB,
        [int]$Depth = 0
    )

    $indent = (" " * ($Depth * 2))
    $children = $SrcParent.GetChildren()
    Write-Output "$indent- Processing source: $($SrcParent.Paths.FullPath) | Child count: $($children.Count)"

    foreach ($child in $children) {
        Write-Output "$indent  - Processing child: $($child.Paths.FullPath) | TemplateID: $($child.TemplateID) | Name: $($child.Name)"
        $templateId = $child.TemplateID.ToString()
        $newItemName = $child.Name
        $newItem = $null

        try {
            # Check if this item already exists by name under TrgParent
            $existingByName = $TrgParent.Children | Where-Object { $_.Name -eq $newItemName }
            if ($existingByName) {
                Write-Output "$indent    - Using existing target item (by name): $($existingByName.Paths.FullPath)"
                $newItem = $existingByName
            } else {
                # Prepare template item
                $templateItem = $null
                if ($templateId -eq $srcFolderTemplate) {
                    $templateItem = $TrgDB.GetTemplate($trgFolderTemplate)
                    Write-Output "$indent    - Using target template (folder): $($templateItem -ne $null)"
                } elseif ($templateId -eq $srcEntryTemplate) {
                    $templateItem = $TrgDB.GetTemplate($trgEntryTemplate)
                    Write-Output "$indent    - Using target template (entry): $($templateItem -ne $null)"
                }
                if (-not $templateItem) { throw "$indent    - ERROR: Target template not found for $newItemName" }

                # Attempt to create under the current TrgParent
                Write-Output "$indent    - Attempting to Add '$newItemName' under $($TrgParent.Paths.FullPath)"
                $newItem = $TrgParent.Add($newItemName, $templateItem)
                if (-not $newItem) { throw "$indent    - ERROR: Failed to add item $newItemName under $($TrgParent.Paths.FullPath)" }
                Write-Output "$indent    - Created item: $($newItem.Paths.FullPath) [ID: $($newItem.ID)]"
            }

            # Recurse or fill entry fields
            if ($templateId -eq $srcFolderTemplate) {
                Write-Output "$indent    - Recursing into folder: $($child.Paths.FullPath)"
                Copy-DictionaryItemsRecursive -SrcParent $child -TrgParent $newItem -SrcDB $SrcDB -TrgDB $TrgDB -Depth ($Depth + 1)
            } elseif ($templateId -eq $srcEntryTemplate) {
                foreach ($lang in $child.Languages) {
                    $srcItemLang = $SrcDB.GetItem($child.ID, $lang)
                    if (-not $srcItemLang) { throw "$indent    - ERROR: Source item language $lang missing for $($child.Paths.FullPath)" }
                    $trgItemLang = $TrgDB.GetItem($newItem.ID, $lang)
                    if (-not $trgItemLang) {
                        $trgItemLang = $newItem.Versions.AddVersion($lang)
                        if (-not $trgItemLang) { throw "$indent    - ERROR: Failed to add language version $lang to $($newItem.Paths.FullPath)" }
                    }
                    $phraseValue = $srcItemLang.Fields[$srcPhraseField].Value
                    $trgItemLang.Editing.BeginEdit()
                    $trgItemLang.Fields[$trgKeyField].Value = $newItemName
                    $trgItemLang.Fields[$trgPhraseField].Value = $phraseValue
                    $trgItemLang.Editing.EndEdit()
                    Write-Output "$indent    - Populated entry ($lang): $($newItem.Paths.FullPath) [ID: $($newItem.ID)]"
                }
            } else {
                Write-Output "$indent    - Skipping unsupported template: $($child.Name) [$templateId]"
            }
        } catch {
            Write-Output "$indent    - ERROR: $($_.Exception.Message) at item $($child.Paths.FullPath)"
            throw
        }
    }
}

try {
    $srcDB = Get-Database $SourceDatabase
    $trgDB = Get-Database $TargetDatabase
    $srcParent = $srcDB.GetItem($SourcePath)
    $trgParent = $trgDB.GetItem($TargetPath)
    Write-Output "Start: Copying dictionary items from $SourcePath [$SourceDatabase] to $TargetPath [$TargetDatabase] ..."
    if (-not $srcParent) { throw "Source parent item not found: $SourcePath in DB: $SourceDatabase" }
    if (-not $trgParent) { throw "Target parent item not found: $TargetPath in DB: $TargetDatabase" }

    Copy-DictionaryItemsRecursive -SrcParent $srcParent -TrgParent $trgParent -SrcDB $srcDB -TrgDB $trgDB -Depth 0
    Write-Output "Dictionary copy completed successfully."
} catch {
    Write-Output "SCRIPT ERROR: $($_.Exception.Message)"
    exit 1
}

Summary & Best Practices

  • Use a single, type-safe useTranslation hook for clarity and safety
  • Always supply fallback defaults to prevent UI errors
  • Prefer shared dictionaries for multi-site projects? Configure fallback domains in Sitecore for reusability
  • Mock dictionary data in Storybook to maintain robust component previews

Hope you find this post helpful!

Using these XM Cloud hotkeys can significantly boost your productivity

Do you use hotkeys? 

I am pretty sure most of you intuitively press Ctrl + S in order to save the changes in Content Editor. Highly likely, you also do any of these below:

  • Del -for deleting an item, and all of its children
  • F2 - rename an item

However, there are plenty of other meaningful shortcuts for you to use:

  • F9 - publish site dialog
  • Ctrl + D - duplicates an item, one of my favorite ever.
  • Ctrl + Win - opens a Sitecore "Start" menu (however, that does not work in 100% of cases)
  • F7 - Validation Results
  • Left / Right keyboard arrows allow expanding and collapsing items' nodes

View togglers:

  • Ctrl + Shift + Alt + R: Toggle raw values. This is one of my best savers when I need to grab an ID for a lookup from a reference field.
  • Ctrl + Shift + Alt + T: Toggle the display of standard fields, which helps improve Content Editor performance when off
  • Ctrl + Shift + Alt + L: Toggle the protection for a selected item.

Content Editor Tabs:

IMG

They typically work as Alt + <first_letter_of_a_tab>:

  • Alt + H: Home
  • Alt + N: Navigate
  • Alt + R: Review
  • Alt + P: Publish
  • Alt + V: Versions
  • Alt + C: Configure
  • Alt + S: Security

 ... but since several tabs start from the same character, less straightforward hotkeys are used:

  • Alt + I: View

 

Predictive search

In Content Editor, hit Ctrl + / and you'll see the bottom right search area activate, waiting for your input. Type in at least two characters for it to progressively show the results, as you keep typing.

 

Mouse Gestures

Dragging and item with Ctrl button held creates a copy of that item right at the location where you release the button.

 

How do I know these shortcuts?

There is a master shortcut Alt + F1 that brings up helpful labels exposing the hotkeys for the specific functions on a Ribbon:

Hope this helps you staying more productive!

XM Cloud productivity tip: Use Cloud Portal Auto Login extension for Chrome

It may be that you're as annoyed as I am by the way certain things are implemented. Imagine you spin up local XM Cloud in containers, type Up.ps1, hit enter, and go away to make some coffee. It typically takes some time while Docker gets updated images and performs the rest of its business, but right in the middle, it gets interrupted by this:

The only purpose of this screen is for you to confirm, simply clicking the "CONFIRM" button, and then keep waiting for approximately the same amount of time you already spent. It won't progress until you actually press this button.

That isn't nice, what a time waster, I thought, and started thinking about the ways of automating clicking the confirmation button, so that the entire Docker start process goes uninterrupted. Created a Chrome extension that appeared to be the easiest one, so there I went.

Then I thought it would be a good idea also to automate submissions to the other screens when you process to the portal, namely this one:

The question comes next question is how to safely keep the email identifier separately from the extension. Browser local storage seems to be a good compromise, so let's go that way. Once users come to the portal for the first time, they enter their email ID as normal. At the time of submission, the extension intercepts the button click and stores the value encrypted. On the next visit to this screen, the value is decrypted and gets automatically submitted into the field by the extension.

I use basic base64 encryption, but with an additional step of character rotation (also known as the Caesar Cipher). This prevents a stranger from a straightforward decipherment of the value taken directly from the local storage. Email ID isn't a very sensitive piece of information, so I am not going wild with protecting its value.

Finally, when the user deliberately logs out by using a drop-down menu from the top right corner, the extension removes the value from the browser's storage. This is done purposely, for example, if one logs out, they usually do that in order to log in as the other user, or maybe they just want out of the system - in any case, we must ensure no further automatic logins persist, and that is exactly what happens.

Currently, it is under moderation in the Chrome store, so you may load this archive by this link and progress with the "Load unpacked" extension, as shown below:

Source code is available here: https://github.com/MartinMiles/cloud-portal-auto-login

Hope you like that one. If you have any comments or thoughts, reach out to me!


Sitecore XP vs XM Cloud full guide: which one to choose in 2025

Index of Content

  1. Introduction
  2. XP vs. XM Cloud differences at a glance
  3. Total Cost of Ownership and Maintenance
  4. Upgrade and Lifecycle Management
  5. Architecture and Hosting Models
  6. Greenfield Projects vs. Existing Implementations
  7. Compliance and Geographic Hosting Considerations
  8. Performance and Optimization Strategies
  9. Conclusion and Recommendations

1. Introduction

In the Sitecore world 2025, organizations face a pivotal choice between the Sitecore Experience Platform (XP) - the traditional all-in-one digital experience platform – and Sitecore XM Cloud, Sitecore's modern cloud-native SaaS CMS. This guide provides an expert breakdown of how these options compare across cost, maintenance, architecture, and capabilities, helping CTOs, architects, marketers, and senior developers make an informed decision. I aim to explain the total cost of ownership, hosting models, upgrade implications, development considerations, and special scenarios (such as greenfield vs. existing implementations, compliance needs, performance tuning, etc.) to cut through marketing fluff and fully evaluate trade-offs.

2. XP vs. XM Cloud differences at a glance

Let's start with the table below that summarizes key differences between Sitecore XP and Sitecore XM Cloud:

Aspect Sitecore XP (Experience Platform) Sitecore XM Cloud (SaaS)
Hosting Model Self-managed on-premises or in your cloud (Azure/AWS VM, PaaS, containers) – full control of servers and configuration. Fully managed by Sitecore as a SaaS multi-tenant service. No direct server management; requires a separate front-end host (e.g. Vercel, Netlify) for site delivery.
Cost Structure Traditional license (perpetual still often met + annual maintenance) plus infrastructure and operations costs. You take cloud/on-prem hosting expenses and support staff. Subscription-based (annual SaaS fee tied to usage/traffic). Sitecore covers core infrastructure. Front-end hosting comes at an additional cost, you’ll pay a provider like Vercel/Netlify for the rendering host.
Upgrades Periodic manual upgrades are required, major upgrades come every ~1-2 years, plus regular patches. These can be large projects, incurring significant time/cost with no direct business feature gains. You control when to upgrade, but falling behind risks end-of-life support. Auto-updated – no manual upgrades at all. Sitecore continuously rolls out new features and fixes. This eliminates costly upgrade projects and ensures you’re always on the latest version. However, you still must accommodate changes in your solution as the platform evolves, for example, updating the rendering host with the latest headless SDKs.
Maintenance & Scaling You manage all infrastructure: provisioning servers, applying OS/Sitecore patches, scaling out for traffic, and monitoring performance. High operational overhead (DevOps, DBA, etc.) is on your team. Scaling requires adding instances or resources, often with lead time and cost. Maintenance offloaded to Sitecore – the SaaS platform handles OS updates, security patches, and scaling automatically. The content delivery occurs via Sitecore's global Experience Edge service, so scaling for traffic bursts is largely transparent. You still manage your front-end app’s scaling (which is solved easily via global hosting providers).
Architecture All-in-one DXP: the CMS, presentation (ASP.NET renderings), and customer data (xDB) live within the same single platform. Can operate in traditional coupled mode or hybrid headless with optional Headless (JSS) Services module. Headless & composable by design: XM Cloud provides content management and an API layer through GraphQL/Edge. No built-in rendering of web pages – a separate "head" (most likely a Next.js app) consumes the content. Embraces JAMstack principles for a fully decoupled front-end. Integration with other SaaS components (such as Personalize, Send, etc.) for marketing features is expected, known as the Composable DXP.
Development Model Typically .NET-centric. Websites are built with ASP.NET MVC or .NET Core (for headless JSS) running within Sitecore. Deep Sitecore knowledge (pipelines, config patches, deployment topology) is required. Smaller talent pool; Sitecore-specific training needed. Extensive backend extensibility, one can write custom processors and integrate deeply. Modern JS/React-centric. Front-end built in Next.js or another framework using Sitecore’s Headless SDK. Common web development skills such as React/TypeScript apply, making it easier to staff projects. Less low-level backend customization – you extend via APIs and webhooks rather than patching Sitecore’s core. Faster local setup by using Docker containers or through connected mode to a cloud instance directly.
Content Editing Rich client interfaces - Sitecore Content Editor and older Experience Editor for inline editing. Familiar to long-time Sitecore users, but can be clunky and slow. Full control of content taxonomy and presentation details, but legacy UI. New Sitecore Pages and Explorer interfaces for content authoring, which are more intuitive, single-page-app style authoring for pages and components. Legacy Content Editor is still available for now. Overall, authoring UX is improved and more streamlined in XM Cloud.
Out-of-the-Box Marketing Features Complete marketing suite: multi-session personalization, user tracking via xProfile/xDB, marketing automation campaigns, email via EXM, path analyzer, etc. All these are included under XP’s umbrella. However, they require significant configuration and infrastructure (for xConnect, processing servers, etc.), and because of that, many organizations underutilize these advanced capabilities. Content-focused: XM Cloud omits the built-in xDB. It offers mostly in-session personalization only (rules that react to the current visit context) and basic analytics. Features like marketing automation, CRM connectors, and email marketing are not included out-of-the-box - you’re expected to use separate SaaS products (such as Sitecore Personalize & CDP, Send, etc.) if you need those capabilities. This keeps the core platform lean but means a composable approach to marketing.
Personalization Depth Robust multi-session personalization: XP tracks each contact’s behavior across visits and builds a rich profile in xDB. You can target content based on historical data, profiles/personas, and engagement values. Great for long-tail personalization, but requires managing the xDB database and GDPR compliance for stored personal data. Session-scoped personalization: XM Cloud’s built-in engine can target content by current context (current page, referral campaign, geolocation, etc.), similar to XM on-prem, but does not remember the visitor once the session ends. For multi-session personalization, you must integrate Sitecore CDP & Personalize, which is sometimes bundled or available alongside XM Cloud. In practice, many XM Cloud adopters add Sitecore Personalize to match or exceed XP’s personalization power.
Compliance & Hosting Flexibility Full control over where and how the system runs. You can host in specific regions or private clouds to meet data residency, GDPR, HIPAA, DORA, or other regulatory needs. If needed, XP can run in a secure on-prem datacenter, within country borders, or even in globally disconnected environments. This flexibility can address strict compliance scenarios, though the effort is on you to secure and certify such an installation. Region selection for data is offered, but you cannot self-host XM Cloud. Sitecore runs it in their cloud (Azure or AWS) with region options to keep customer data in a chosen geography. Sitecore’s cloud is certified (ISO 27001, SOC2, etc.). However, if you have an extreme requirement like an air-gapped network or a country with no approved region, XM Cloud may not be viable.
Support Lifecycle Sitecore has committed to continuing XP/XM on-prem support for several years. For example, XP/XM 10.4 will have mainstream support until the end of 2027 and extended support until 2030. This gives existing XP users a runway to remain on-prem for now. However, older versions will hit end-of-life sooner, forcing upgrades to stay supported. Long-term, Sitecore’s strategic focus is on cloud offerings, so new features will tilt toward XM Cloud and composable products. As a SaaS product, XM Cloud is continuously supported and updated by Sitecore. Subscribers are always on a supported version by definition. Sitecore’s roadmap for new capabilities is heavily invested here, so XM Cloud users will see the lion’s share of innovation going forward.

Table: High-level comparison of Sitecore XP vs. Sitecore XM Cloud in 2025.

As the table suggests, XM Cloud represents a shift to a cloud-native, headless, and service-based paradigm. Meanwhile, XP offers a do-it-yourself, all-in-one environment with maximal control and integrated features (at the cost of complexity). The following sections dive deeper into specific considerations: cost of ownership, greenfield vs. migration scenarios, compliance constraints, and optimization strategies for performance and deployment.


3. Total cost of ownership and maintenance

Licensing & Subscription Costs: One of the first factors to evaluate is cost. Sitecore XP traditionally involves a sizeable license fee, often perpetual or long-term, plus annual maintenance fees. If you already own an XP license, you might only be paying maintenance annually. In contrast, Sitecore XM Cloud is sold as a subscription SaaS product - you essentially pay for a recurring subscription that includes the software and its managed hosting. The XM Cloud subscription cost is generally usage-based, simplified to factor in traffic, number of Content Management environments, etc., which can be a double-edged sword: if your sites see very high traffic, the SaaS fees might scale up, but for moderate usage, you pay only for what you need. XP’s costs, on the other hand, are more fixed in terms of licensing, but infrastructure costs are on you - cloud VMs, SQL licenses, content delivery servers, etc., all that adds to the TCO.

Infrastructure & Operations: With XP, you bear the cost of infrastructure and IT operations. This means provisioning servers (or Azure App Services), managing SQL databases, search servers (Solr), CD servers behind load balancers, plus the manpower to monitor and support them. You might need skilled infrastructure/DevOps personnel or a managed cloud contract. By contrast, XM Cloud shifts most of that burden to Sitecore. The subscription includes the managed Sitecore Cloud portal and hosting of the core CMs and Experience Edge. You don’t pay separately for SQL or Solr – those are hidden behind the actual SaaS product. Operational tasks like OS patches, security updates, scaling infrastructure, and performance tuning at the server level are handled by Sitecore. This can dramatically reduce the maintenance labor on your side and thus lower the operational cost by eliminating the need to manage and maintain your own infrastructure.

However, note that XM Cloud doesn’t include the front-end delivery environment – you still need to host the actual website application (the “head”) on a platform of your choice. For example, if you build a Next.js site, you might host it on Vercel, Netlify, etc. That hosting cost is separate and must be added to your TCO calculations. In an XP scenario, your "front-end" and content delivery are part of the same hosting cost for your CD servers. In XM Cloud, the CMS is hosted by Sitecore within an included subscription, but the rendering host is not. The upside is that front-end hosting, especially static/JAMstack (SSG) apps, can be very cheap and scales with usage. Many find the cost of Vercel to be relatively low compared to keeping multiple high-spec Sitecore CD servers running 24/7.

Upgrades & Lifecycle Costs: Perhaps the biggest cost saver for XM Cloud is the elimination of version upgrade effort. With XP, every few years you face a significant upgrade effort – planning, regression testing, updating custom code, and sometimes content migrations – just to stay on a supported version. These projects incur not only services cost but also opportunity costs - time that could be spent building new features. As an example, a typical enterprise XP upgrade (say from 9.x to 10.x) could take months of work. XM Cloud goes away with this - Sitecore handles all upgrades in the background, delivering improvements continuously. For the customer, this simply means "no more Sitecore upgrades", which brings huge savings in money and time. You’ll always say on the latest version without dedicating effort and budget to get there.

From a lifecycle perspective, Sitecore has committed to supporting XP for several more years - XP 10.4 mainstream support until the end of 2027, and extended to 2030. So you won’t be forced off XP immediately. However, continuing to use XP means you likely will need to upgrade to 10.4 if you haven’t yet, to enjoy that support window, which itself is a near-term cost if you are on an older version. In contrast, XM Cloud’s evergreen nature means the concept of end-of-life is moot – you’re always current. The cost implication is that while you save on periodic upgrade projects, you do need to invest continuously in keeping your solution compatible by testing your integration and front-end when Sitecore updates the backend. Fortunately, backward compatibility in XM Cloud is maintained carefully, and changes are incremental.

Personnel and Skills: Cost of ownership also ties to the team required. Running XP often demands Sitecore-specialized developers, DevOps, server admins, and possibly managed services contracts, which can be costly. XM Cloud shifts the required skill profile: you’ll need front-end developers and perhaps cloud architects familiar with modern deployment, but you might reduce the need for full-time Sitecore ops experts. As noted earlier, the pool of JavaScript/Next.js developers is way larger and often less expensive than the niche pool of Sitecore backend developers. This can lower staffing costs or allow your existing team to focus on front-end innovation rather than low-level CMS tweaks.

In summary, XM Cloud tends to have a lower operational cost and a more predictable subscription model, whereas XP might have a lower software cost if you already own licenses but will incur higher maintenance effort. When calculating TCO, consider a multi-year horizon: XM Cloud’s subscription plus front-end hosting vs. XP’s license and maintenance plus the cumulative cost of VMs, support contracts, and an eventual upgrade. Many organizations find that when factoring in the soft costs (downtime, upgrade labor, performance tuning), XM Cloud delivers savings. But every case is unique – if your XP environment is stable, paid for, and lightly maintained, and your organization isn’t in a position to invest in re-development, the pure dollar savings of XM Cloud might not be realized until further down the road.


4. Upgrade and Lifecycle Management

Upgrades have been the pain for many Sitecore teams historically. With XP, you control if and when to upgrade, but you must upgrade eventually to stay supported, and those projects can be major undertakings. Sitecore XP/XM platforms 10.4 are the "last" of on-prem releases as of today, and Sitecore has pledged continued support, up to 2030, with extended support, which means orgs can comfortably stay on XP 10.4 for the next few years with regular support. If you’re on an earlier version (e.g., 9.3 or 10.1), you will have to upgrade to at least 10.4 to stay within that window, which means a near-term effort anyway. Some companies are choosing to do that upgrade, then evaluate moving to XM Cloud later, while others are considering leaping straight to XM Cloud instead of executing another on-prem upgrade.

XM Cloud’s model is a huge change - you avoid the cycle of "wait for new version -> plan upgrade -> execute -> troubleshoot". From a lifecycle management standpoint, this is a relief: your platform is always current and fully supported. Sitecore delivers updates in a backward-compatible way and typically provides notice of any breaking changes. As a customer, you’ll want to have a process to validate your solution against new releases, but you won’t need to allocate large budgets for these updates.

One thing to consider is data and content migration in the context of moving to XM Cloud. If you are currently on XP and decide to replatform to XM Cloud, that migration project essentially stands in place of an upgrade project. Content can be serialized and migrated, and most customers can bring over all their content, media, and templates into XM Cloud relatively intact, meaning Sitecore has ensured backward compatibility in the content schema. But as we’ll discuss below, your custom code and front-end are not portable as-is. This is less about the platform upgrade and more about rebuilding on a new architecture.

Another lifecycle aspect is vendor support and roadmap. Sitecore’s roadmap for on-prem XP beyond version 10.4 is expected to be mostly maintenance and minor improvements, whereas XM Cloud and the composable SaaS products will get the bulk of innovation - AI-driven authoring assistance, new integrations, etc. If having the latest and greatest features is important, XM Cloud aligns with that path. If your priority is a stable, unchanging platform, XP can offer that at the cost of eventually aging technology.

Finally, consider how compliance regulations like DORA impact the lifecycle. For financial services in the EU, DORA requires that ICT providers (like Sitecore, if you use XM Cloud) adhere to strong resilience and incident reporting. Sitecore is not directly under DORA as a non-financial entity, but they have updated agreements to help customers comply. For an XP on-prem installation, you, as the operator, would bear the burden of meeting operational resilience standards. That includes doing regular disaster recovery drills, ensuring you can recover from incidents, etc. In a sense, letting Sitecore handle that via XM Cloud could simplify compliance - they state they offer "robust security measures to ensure resilience and availability" and will support customers’ DORA obligations. However, some organizations may prefer the control of managing their environment to meet specific internal policies. It’s a trade-off between trusting the vendor’s managed service vs. doing it yourself under your own compliance regime.

Bottom line on upgrades: If you are tired of the upgrade treadmill, XM Cloud is extremely attractive – it ends the cycle of expensive upgrades and ensures you’re always up-to-date. If, on the other hand, you like having full control of when to change your system (like some enterprises freeze tech changes for long periods), XP allows you to stay static despite being unsupported after a point. Many see the writing on the wall that by 2025 and beyond, continuously updated SaaS is the norm, and planning for that model (with proper testing processes) is wiser than clinging to a static version. Sitecore has given XP a generous support timeline, so there’s no immediate panic to switch, but the advantages of not having to plan another upgrade are compelling to most.


5. Architecture and Hosting Models

The architectural differences between XP and XM Cloud are fundamental. Sitecore XP is a monolithic application in the sense that all its services - content management, content delivery, processing, tracking - work together as a single product suite running in a single environment. They can certainly be scaled out individually (multiple CD servers, separate roles), but it remains one big platform under your control. Sitecore XM Cloud is a cloud-native SaaS that embraces a decoupled architecture: the content backend and the presentation frontend are completely separate by design.

Hosting Flexibility (XP): With XP, you have numerous hosting options. You can deploy on-premises on your own hardware, in a private cloud, or on public cloud IaaS. Some run XP on Azure PaaS with Sitecore Managed Cloud platform-as-a-service hosting of XP, or even containerize it on Kubernetes. Single-tenant is the norm – your Sitecore installation is dedicated to you, even if managed by a third party. This flexibility is a double-edged sword: you can satisfy unique requirements (custom networking, specific region, or even specific servers for compliance, integration with legacy systems, etc.), but you also have to manage all the complexity that comes with it. If you need to, for example, deploy a content delivery instance in China or in a DMZ environment, XP lets you do that.

Hosting Model (XM Cloud): XM Cloud is only offered as SaaS by Sitecore – you cannot host XM Cloud yourself. It runs in the Sitecore cloud environment, leveraging Azure and AWS under the hood. It’s a multi-tenant (many customers on the same SaaS platform, logically separated). You get an organization and project space in the Sitecore Cloud Portal where you can create environments, typically production, staging, and development. Sitecore handles provisioning those, and you simply deploy your code and content. There is no concept of installing Sitecore on your server - instead, you deploy your serialization packages and front-end builds to their service. The front-end rendering host, however, is your responsibility to host. The typical pattern is to use a JAMstack approach: for example, host the Next.js app on a platform like Vercel. In fact, Sitecore specifically encourages using Vercel or Netlify for XM Cloud front-ends, noting that these platforms are specifically designed for high-performance websites and integrate very well. Some companies choose to host the front-end themselves, for example, on an internal Kubernetes cluster or Azure App Service, but Sitecore guidance is to leverage modern cloud hosting for that purpose, achieving the best results.

Implications for Cloud-Native Services: Because XM Cloud decouples the roles, you gain the ability to use cloud-native edge networks out of the box. With XP, if you wanted to use an edge CDN or a service like Vercel’s edge functions, you had to configure that on top of Sitecore, often in a limited way. In XM Cloud, the Sitecore Experience Edge service gives globally replicated content APIs, and your front-end can be deployed globally as well. This means things like SSR (Server-Side Rendering) can happen at edge nodes close to users, and static content can be cached on CDNs easily. In XP’s traditional model, the content delivery server itself often lived in one region, or a couple of regional data centers you set up, so global users might have higher latency unless you implemented your own CDN caching layer. XM Cloud largely solves global delivery by design.

Content Delivery Differences: In XP, content delivery is handled by Sitecore’s own ASP.NET application at the CD server running the site. In XM Cloud, content delivery is headless - the CMS does not directly serve end-user pages. Instead, it exposes content via GraphQL APIs, and a separate rendering host application generates the pages. This means if you choose XM Cloud, you are committing to a headless architecture for your sites. The benefit here is flexibility and performance. The trade-off is that assembly effort is required - you have to build a front-end application to consume the content. In XP, if you used something like Sitecore SXA or MVC, a lot of the presentation came out of the box. In XM Cloud, Sitecore provides starter kits for Next.js and other systems, but you will be building the presentation layer with a front-end framework, not with Sitecore’s layout engine. This is a key consideration: organizations comfortable with modern front-end development will see this as liberating; organizations that liked Sitecore’s all-in-one approach to layout and rendering will have to adapt.

DevOps and Environment Management: In XP, you might have multiple environments (dev, QA, prod), each as separate Sitecore instances you manage. With XM Cloud, Sitecore provides environment slots for you. For example, a typical XM Cloud subscription might include 3 environments (production, and two non-prod like UAT and integration). These are easily spun up via the portal. The deployment process is built-in: you connect a source repository (GitHub or Azure DevOps) to the Sitecore Deploy App, and it can automatically build and deploy your code to the XM Cloud environments. This is a more streamlined DevOps experience compared to manually deploying items and code to an XP server. It even de facto supports blue-green deployments for zero-downtime releases when the platform can keep the previous instance running while swapping in the new one.

For a technical team, this means less time setting up build/release pipelines from scratch - Sitecore provides a lot of that out of the box in XM Cloud. For XP, you typically need to create CI/CD scripts or use tools like Octopus Deploy to deploy Sitecore packages, and coordinate things like content serialization, etc., which is more effort.

Extensibility and Customization: In a traditional XP solution, developers can deeply customize the system – pipeline processors, custom Sitecore jobs, and low-level tweaks to how the CMS behaves. With XM Cloud, because it’s a managed SaaS, you should not modify core pipeline code on the server. Customization is achieved either through high-level configuration or by writing code in the front-end or external services. For example, if you had a complex content cleansing pipeline on item save in XP, in XM Cloud, you might implement that via a webhook or by a scheduled external function that uses the GraphQL content API to enforce rules. You also currently cannot use some XP modules or custom Solr indexes in XM Cloud. This means heavy customizations might need re-architecture. The advantage is that you are constrained to more upgrade-safe approaches, but the disadvantage is less freedom to bend the platform to unique needs. This is an architectural philosophy shift: XM Cloud aims for configuration over customization to maintain stability in a multi-tenant cloud.

Hybrid Possibilities: It’s worth noting that some organizations consider a hybrid approach - keeping an on-prem XP for certain sites or functions while starting to progressively build new experiences on XM Cloud. Sitecore's composable lineup is designed to allow mixing: for instance, you could continue using XP for its xDB-driven personalization on an existing site, but launch a new microsite on XM Cloud + Sitecore Personalize and perhaps have both share the same Sitecore CDP for customer data. This is complex, but it highlights that choosing XM Cloud doesn’t necessarily mean abandoning everything at once. That said, running two parallel CMS platforms has its own cost and is usually a temporary state.

In summary, architecturally, XM Cloud is aligned with modern cloud architecture principles - multi-tenant SaaS, globally distributed delivery, microservices, content as a service, personalization as a separate service, etc., whereas XP is a single-tenant application architecture that you tailor to your environment. If your organization values complete control over the hosting environment and data flow, XP offers that, you can even access the database directly, etc., which you absolutely cannot do with XM Cloud. If instead you value simplicity, scalability, and cloud-first design, XM Cloud clearly leads. One key question: Do you require on-premises or specific-region hosting that Sitecore doesn’t support? If yes, that’s a strong case for XP, or at least XM on Managed Cloud, which still gives region control. For example, if you need to host in mainland China for a China site (due to ICP license rules), XM Cloud hosted on Western infrastructure will face significant performance challenges in China and potentially legal barriers, whereas XP could be stood up in China for example on Azure China or Alibaba, to comply. I will talk you through compliance and geographic requirements below.

Choose XM Cloud when you want to offload ops, speed launches, and lock in predictable costs and continuous updates. Stay on XP or self-hosted XM if you need full control over data residency due to the specific compliance/regulations requirements for your organization, have heavy legacy code, or require advanced multi-session personalization today. Either way, your path should match your team’s skills, your compliance needs, and your growth plans.


6. Greenfield Projects vs. Existing Implementations


The decision process can differ significantly if you’re starting a brand-new project (aka greenfield) versus if you have an existing Sitecore XP solution. Let’s address both scenarios:

6.1 Greenfield Projects – When to Choose XM Cloud or XP?

For new digital experience initiatives, the general industry momentum and Sitecore’s own strategy favor XM Cloud. If you are not weighed down by legacy, XM Cloud often makes sense because you can architect from scratch with modern best practices and won’t have to redo things later to keep up with Sitecore’s cloud direction. Key considerations:

  • Time to Market & Initial Setup: XM Cloud can be provisioned quickly due to no need to install Sitecore or set up servers. For a new project, this means you get a working CMS environment in days, not weeks. You can also leverage starter templates, such as Sitecore’s Next.js starter kit, to jumpstart development. If speed is critical, this agility is valuable. XP, by contrast, would require setting up at least a CMS and CD server, installing the software, configuring scaling, etc. - a slower ramp-up.

  • Future-Proofing: A new project built on XP in 2025 might risk becoming technical debt sooner. Sitecore’s major innovations (e.g., new AI content features, deeper integration of Content Hub, etc.) will likely be cloud-first. Adopting XM Cloud means you’ll automatically get those enhancements. With XP, you might find in a couple of years that the capabilities lag behind unless you integrate additional SaaS components anyway. Starting on XM Cloud sets you on the vendor’s forward-looking path from day one.

  • Team Skill Set: Starting a greenfield on XM Cloud is ideal if your development team (or your implementation partner) has strong React/Next.js skills and is comfortable with headless CMS concepts. Many agencies and new developers prefer working with the JAMstack approach as it aligns with modern development practices. If, hypothetically, your team were mostly back-end .NET developers with no modern front-end experience, they might have a learning curve. However, given industry trends, most teams have adapted or can pick up Next.js fairly quickly. Sitecore XP development with MVC and Razor might actually be harder to ramp up for new developers who lack a Sitecore background, whereas XM Cloud development can be more approachable since it uses familiar web tech and just calls an API for content. So, for new projects, assessing your technology comfort is important. In almost all cases, though, I would advocate building new experiences with headless architecture to avoid being stuck in older paradigms.

  • Organization Strategy: If your organization has a cloud-first mandate or is embracing SaaS for other systems (CRM, commerce, etc.), starting on XM Cloud fits well. If, instead, there is still a preference for on-prem control (some government or defense projects, for example, might not be ready to put content in a SaaS), then XP could be chosen to satisfy that policy. But in 2025, even regulated industries are increasingly allowing SaaS for CMS after due diligence, because CMS content is often not highly sensitive data (with exceptions). It’s more common to see resistance to cloud for things like customer data, but note, XP itself stores customer data (xDB), whereas XM Cloud (without CDP) does not store much personal data by default. In a way, XM Cloud can be easier to get through security review than XP because it’s mostly content-focused (pages, text, media) rather than PII.

In summary, for new projects, XM Cloud is usually the recommended choice unless you have a very unique reason to deploy and manage everything yourself. It offers faster setup, easier scaling as you grow, and avoids locking you into legacy architecture. One might still choose XP for greenfield if, for example, the project is an internal application that must run on an internal network with no external cloud dependencies, or if the feature set of XP aligns perfectly without needing any of Sitecore’s composable add-ons, and you want to avoid a multi-system solution. But those cases are increasingly rare. Most new digital experience builds want a modern, performant, and low-maintenance foundation, which XM Cloud provides.

6.2 Existing Sitecore Implementations – Stay on XP or Move to XM Cloud?

If you already have a Sitecore XP or XM solution running, the question becomes when or whether to migrate to XM Cloud. This is a complex decision with technical and business angles:

Assess Feature Usage: A critical first step is to determine how much of the XP platform you are actually using. Many Sitecore XP customers purchased the platform for its potential (personalization, xDB analytics, etc.), but over time, ended up using it mostly as a robust CMS, with minimal use of the fancy marketing features. It’s noted that very few organizations have the operational capacity to make full use of XP’s personalization capabilities, not to mention marketing automation. If you find that you are not leveraging xConnect/xDB (no custom profiles, no multi-session personalization rules, no marketing automation campaigns running), effectively, you might be using the XM subset of features already. In that case, moving to XM Cloud will not strip your solution of capabilities you actually use - it will likely be a smoother transition functionally. On the other hand, if you heavily depend on, say, Sitecore Marketing Automation for personalized email campaigns, or you have dozens of personas with tailored experiences on the site based on past behavior, you need to plan how those will be re-implemented. XM Cloud alone won’t provide those; you’d need to bring in Sitecore CDP & Personalize, Sitecore Send (for email), etc., as part of the migration. That introduces additional cost for separate subscriptions and effort to integrate. The upside is that those composable tools are more advanced in their domains, for instance, Sitecore Personalize can do real-time, AI-driven personalization across channels, which could outperform what you built on XP, but it takes work to configure.

Migration Effort – Front-end Rebuild: It must be stated plainly: moving from XP to XM Cloud is not an in-place upgrade; it is essentially a re-implementation: a whole new frontend must be established on a new technology. This is crucial to set expectations with stakeholders. If your existing site was built with MVC and Razor views in Sitecore, those renderings will not run on XM Cloud’s Next.js front-end. You will need to rewrite the presentation layer. Content can be migrated, and your content and templates are intact on the new side, which is a relief, but all the code that rendered that content in XP (layouts, rendering, controllers, etc.) must be redone in the new stack. If you have a large, complex site, this is a non-trivial effort.

On the bright side, you can reuse assets: HTML markup and CSS can largely be carried over into the new front-end, also any client-side JS logic can often be reused. It’s the server-side C# logic that must be translated into the React/Next.js world. Many find that this is an opportunity to clean up and modernize. Maybe your site’s UI could benefit from a refresh - some clients time the migration with a minor redesign so that rewriting the front-end yields a better UX as well. If you recently did a heavy investment in a new XP-based site (e.g., a big redesign last year on XP), the thought of rebuilding it so soon may be unwelcome. In that case, sticking with XP a bit longer to get the value out of that investment is understandable. If your site is due for a redesign or technology refresh anyway, that’s an ideal time to combine it with a move to XM Cloud.

What if you already built your XP site in a headless/hybrid way? For example, some XP projects in recent years used Sitecore JSS with React, essentially treating XP as a headless content source. Such a project is much easier to migrate - in fact, your front-end code (React app) could probably connect to XM Cloud with minimal changes. Just point to the new GraphQL endpoint and adjust API keys. If you’re in that fortunate situation, the migration becomes more about moving content and testing rather than rewriting everything. Essentially, you’d be swapping the content backend from XP to XM Cloud and perhaps replacing XP-specific services (like if you used xDB data, you’d swap to CDP).

Integration and Customization Migration: Look at any integrations your XP solution has - say, CRM integration, eCommerce integration, search providers, etc. If those were done via direct access to XP databases or internal APIs, they’ll all need to be redone to use XM Cloud’s APIs. If you used something like Sitecore xConnect to push data to CRM, in XM Cloud, you might instead use a combination of Sitecore Connect or direct API calls to CDP. Also, any custom modules (perhaps you built custom workflow actions, or you extended the Experience Editor with custom buttons) must be evaluated. Some may not be possible in XM Cloud yet. For instance, Sitecore Forms were not initially supported in XM Cloud - a workaround was required for forms in headless apps. These gaps are closing as Sitecore invests in XM Cloud, for example, forms support was added later, but it underscores that a migration requires a thorough gap analysis.

Cost-Benefit Analysis: From a business perspective, you must weigh the cost of staying on XP vs. migrating to XM Cloud. Staying on XP is not "free" - you will likely need to upgrade to keep support (cost), you continue to run servers (cost), and you may be missing out on performance or productivity gains (opportunity cost). Migrating has an upfront cost of rebuilding and retraining, but promises savings and improvements after. One recommended approach is to build a business case enumerating these factors. For example, if moving to XM Cloud will eliminate $X of hosting costs annually and $Y of upgrade costs every few years, and perhaps increase conversion by Z% due to better performance, can those justify the migration project expense in ROI terms? Often, after a few years, the migration pays for itself just in savings. It’s not always purely financial; agility and future readiness are part of the value.

Organizational Readiness: Change management is also important. Your content authors will have a new interface (though not drastically different, and likely more user-friendly). Your IT team’s responsibilities shift - some roles (server admin) might be less needed, while others (front-end DevOps) become key. You may need to train developers on Next.js and familiarize them with XM Cloud tooling (CLI, serialization via Git, etc.). If your team is not ready, consider investing in training or engaging with a Sitecore partner who has done XM Cloud projects. Some organizations pilot XM Cloud on a smaller project first (migrate a microsite or lesser-trafficked site) to build experience, then tackle the main site. This can de-risk the process.

Gradual Migration vs. Big Bang: You do have the option to move in phases. You could start by downgrading XP to XM, turning off xConnect on your existing instance, and essentially running XP as if it were XM with only in-session personalization. This could simplify your current environment (no xDB) and get authors used to less personalization. Then you could move that to XM Cloud. Or, you could migrate one site at a time if your XP instance hosts multiple sites. In some cases, organizations keep XP running for a period for certain functions (like serving personalization to known users) while launching a new site on XM Cloud for anonymous or new audiences, and then gradually phase out XP. These approaches add complexity but reduce risk by avoiding an all-or-nothing switch on day one.

When does it make sense to stay on XP? After all this, there are valid reasons some will stay on XP in 2025:

  • Regulatory Constraints: If you absolutely cannot use a SaaS for CMS due to data control requirements, say for some government agencies or in highly sensitive content scenarios, then XP or perhaps XM in a self-managed mode is the way to go. You maintain full control and can deploy in hardened environments as needed.

  • Full Use of XP Features: If you are one of the few that deeply use XP’s marketing suite and it’s running well, you might not want to break what's working. For example, if you have a mature personalization program leveraging historical profiles and automated campaigns that drive real ROI, you might decide to stick with XP until Sitecore’s composable equivalents prove they can meet or exceed that functionality with acceptable cost. In parallel, you might start testing Personalize or CDP to see if a switch is feasible later.

  • Short-term Horizon or Alternative Plans: If your organization is, say, 1-2 years away from a broader digital transformation or considering alternate platforms, you might not undertake a migration to XM Cloud now. For instance, some companies on XP are evaluating not just XM Cloud but also competitors or more lightweight CMS options. If you haven’t decided on the long-term platform, you may prefer to keep XP running "as-is" (with maybe a minimal upgrade) as a stop-gap until a larger replatform decision is made. XM Cloud is one path, but some XP customers could even decide to move to a completely different CMS, though that also is a rebuild. It’s outside our scope, but it’s worth acknowledging that XP customers should evaluate all options – in other words, moving off XP doesn’t only mean XM Cloud; it could mean a competitor’s SaaS. Of course, as a Sitecore guide, we focus on XM Cloud as the intended upgrade path.

  • Budget Constraints in the Near Term: If the migration cost cannot be justified or funded this year, you might delay until budget allows. In the meantime, ensuring you’re on a supported XP version and maybe optimizing that environment is reasonable.

When does it make sense to move to XM Cloud from XP? Generally:

  • When you realize your team is spending more time "keeping the lights on" with XP (patches, Azure costs, troubleshooting scaling issues, etc.) than on building new digital value. XM Cloud frees you from a lot of that maintenance toil.

  • When site performance or deployment pain is holding back your digital efforts, and you see that a headless, cloud-native architecture will alleviate those, which it often does, as we’ll cover in optimization.

  • When the cost of Sitecore XP (license + infra) compared to the value you get is being questioned, and moving to XM Cloud either reduces cost or increases value (for example, giving marketers a faster way to launch pages, which can translate to business revenue gains).

  • If your organization has adopted a composable stack approach – for instance, you already use a separate commerce engine, a separate DAM (Content Hub or others), maybe a separate analytics tool – then XP’s all-in-one value is less important, and XM Cloud will integrate better with a composable ecosystem.

  • If you’re looking to modernize the solution, maybe your XP implementation is 5-6 years old, design is stale, and technical debt is high; it might be easier to start fresh on XM Cloud than to upgrade and refactor an aging XP codebase.

One more angle: XM Cloud vs. XP "as XM". Some customers on XP have the option to downgrade their license to XM (content-only) and possibly stick with self-managed XM, which is XP without xDB. This can save license costs while still running the instance yourself. However, that approach gives up the tracking features but keeps the hosting burden. It’s a half-measure that some use if they want to stop running xDB but aren’t ready to go SaaS. In deciding XM Cloud vs staying on XP, consider if running XP just as a CMS is worth it compared to XM Cloud – likely not, because all the maintenance remains, but you’re not leveraging XP’s unique features. In such a scenario, XM Cloud is a better target to eliminate the maintenance as well.

Conclusion for existing implementations: Evaluate what you use, what you gain, and what you’ll spend in a migration. If your XP implementation is underused (typical case: using it as an expensive CMS), the argument to migrate is strong – you can likely cut costs and improve performance by shedding the xDB weight and moving to XM Cloud. If your XP implementation is delivering on its promise and deeply embedded in your marketing operations, plan a migration more cautiously - perhaps wait until Sitecore’s composable tools mature further or do a pilot. But keep an eye on the support timeline; even the best XP 10.4 implementation will face end of mainstream support by 2027. For many, the question is not if to move to XM Cloud or a similar SaaS model, but when - doing it proactively, on your terms, is better than being forced later under time pressure.


7. Compliance and Geographic Hosting Considerations
Every organization must consider regulatory requirements, and the CMS platform choice can be influenced by how well XP or XM Cloud meets those needs. I have discussed several common compliance and localization factors in a separate blog post.



8. Performance and Optimization Strategies on XP vs. XM Cloud

One of the most tangible differences teams experience is in site performance, scalability, and the effort needed to optimize each platform. Both XP and XM Cloud can deliver high-performance experiences, but the approaches differ.

Out-of-the-Box Performance

Sitecore XP: In its traditional mode, XP generates pages server-side for each request unless heavily cached. The performance of your site is tied to the power of your content delivery servers and how well the code and caching are implemented. XP sites can be optimized to be fast, but it requires tuning: item caching, output caching for components, preloading data, etc. Even then, achieving near-instant page loads globally is challenging because the content has to be fetched from the server, which might be far from the user. Many XP implementations struggled to achieve top-tier Google Lighthouse or Core Web Vitals scores due to the inherent overhead of server-side assembly and the weight of the Sitecore rendering pipeline. Getting legacy architectures to match the performance of static sites is extremely difficult.

Sitecore XM Cloud: Performance is a strong point here because of the headless JAMstack approach. Websites built on XM Cloud are typically either static, pre-generated, or server-side rendered at Edge, both of which can drastically reduce latency to users. For example, with Next.js, you can pre-build pages (Static Site Generation) so that they are just HTML files served via CDN, yielding extremely fast first-byte times. Or you use Incremental Static Regeneration (ISR) to update content periodically while still serving cached pages. Even for dynamic content, SSR on a platform like Vercel runs on a global edge network. The result is that an XM Cloud-based site can be as snappy as a static website for most users. It’s common to see improved performance and scalability immediately by moving to a headless architecture - many teams report that after moving to a Next.js + XM Cloud setup, page load times and Lighthouse scores improve dramatically.

Caching and Content Delivery Networks (CDN)

XP Caching: XP supports output caching at the Sitecore rendering level where you can cache renderings by varying criteria, and has a robust object caching for items, media, etc. Using a CDN like Cloudflare/Akamai in front of XP can offload static assets (images, CSS, JS), but caching full HTML pages on the CDN is harder if personalization or login-specific content is involved since pages aren’t one-size-fits-all). Some XP deployments did set up whole-page CDN caching for public pages and used cache-busting or short TTLs to balance freshness. But doing so requires careful configuration to avoid serving the wrong personalized content to users.

XM Cloud + CDN: Here, the CDN (or edge) is integral. When you deploy your front-end on, say, Vercel, it automatically serves content via their CDN nodes around the world. If you pre-render pages, they are essentially static and cached indefinitely until revalidated. Out-of-the-box personalization in XM Cloud is largely in-session, meaning a cached page can be the same for all users, and then personalized bits can be swapped in after load (for instance, via client-side rendering of a personalized component). This strategy means you don’t forego caching for personalization – you just handle it differently with either edge logic or client logic. Additionally, XM Cloud’s Experience Edge caches content data globally, so the API calls themselves are fast. The result: high cache hit ratios and use of edge computing are standard with XM Cloud solutions. You might still fine-tune cache headers and revalidation logic (Next.js provides good controls for ISR and stale-while-revalidate patterns), but overall, achieving global low-latency delivery is simpler.

Scalability

XP Scalability: XP typically scales vertically or horizontally by adding more CD instances behind load balancers. It can handle a high load if properly scaled out, but it requires you to provision enough servers for peak load or use auto-scaling on cloud VMs. There’s also the scaling of the xConnect collection role to consider if you track many interactions – the xDB processing can become a bottleneck under heavy traffic with personalization. Many XP users have experienced that to handle spike traffic for a big one-off event or campaign, they need to spin up additional CD servers and ensure the caching is warmed, etc. That incurs cost for those peak times. Also, session state management and such need to be configured (sticky sessions or a distributed session state server) if using personalization per session.

XM Cloud Scalability: The content management and Edge APIs of XM Cloud are scaled by Sitecore automatically – they run in a cloud that can scale out to meet API demand, and Sitecore handles this as part of the service. Your front-end on Vercel or Netlify scales virtually infinitely - these services deploy your site across countless edge nodes. The result is that handling a spike in traffic is usually seamless: the CDN serves most content without hitting the origin; if many users hit uncached pages, the edge functions scale out. You don’t wake up at 2 am to add servers – it’s handled. There are limits (like API rate limits), but they are quite high, and you can engage Sitecore if you expect an extraordinary load, as they can provision accordingly. In short, scalability is a solved problem in the XM Cloud model: you pay for what you use, but you rarely worry about collapsing under load. Anecdotally, if a marketing team does a huge product launch, an XP setup might require careful load testing and pre-scaling; an XM Cloud setup, if built right, just flows that traffic through global CDNs.

One consideration: in XM Cloud, if you have heavy server-side compute logic in the rendering (like complex data mashups in getServerSideProps in Next), you’ll want to ensure your hosting platform can handle it. But generally, those computations are lightweight compared to what XP’s server did, generating full pages with personalization rules.

Personalization and Performance Trade-offs

XP Personalization: In XP, the more you personalize, the more cache fragmentation you get - every unique combination of personalization rules can cause a cache miss and trigger fresh page generation. This often forced teams to limit personalization to small regions or use "don’t vary by user" on most components. Also, tracking every visitor interaction had a performance cost on the xConnect/shard databases. Many XP sites for performance reasons ended up turning off or limiting xDB tracking on high-traffic pages, or doing personalization only on a subset of pages.

XM Cloud Personalization: With XM Cloud’s embedded in-session personalization, which, under the hood, leverages a lightweight CDP edge instance, personalization is applied at request time but for that session only. For example, you can have a component that shows one variant for visitors coming from Google Ads vs another variant for others - this check can be done on the server (Next middleware or Sitecore’s Edge returns the variant), but the result can still be edge-cached for that session. If using Static Generation, personalization might be applied client-side. Sitecore provides a Personalize JS SDK for XM Cloud that can swap components after page load based on session rules. This means you don’t bust the CDN cache for every user scenario - you might serve the general page and then immediately personalize it in the browser. The result is you keep the fast delivery for everyone, with a slight delay for personalized content loading asynchronously.

If you integrate the full Sitecore Personalize (the SaaS), personalization runs via client-side or edge decision-making, separate from page generation. That tool is built for scale; it can handle high volumes of events and decisions at the cost of some complexity. The user experience can still be very performant because Personalize can respond in tens of milliseconds with a decision, which can be done at Edge or client. Plus, Personalize allows experimenting with different performance vs. personalization trade-offs, like using web experiments that load after initial page vs. pre-personalizing content.

In short, XM Cloud allows high performance and personalization, but requires a different implementation approach (client/edge dynamic behavior vs. server-side rendering per user). XP allowed convenient server-side conditional rendering, but beyond simple rules, it could slow things down or reduce caching.

It’s telling that many XP customers never fully used the multi-session personalization because of the operational overhead; they effectively treated XP like XM. Now with XM Cloud plus Sitecore Personalize, those who truly need advanced personalization can have it without burdening the content delivery pipeline for every request – it’s offloaded to a specialized service optimized for that, leaving the main site free to be cached.

One must plan this carefully, though: initial implementations of XM Cloud might just use in-session rules and feel less powerful than XP’s historical personalization. To exceed XP, you’d include Sitecore Personalize, which opens up things like AI-driven segments, but you have to wire it up (the tracker snippet, etc.). From a performance standpoint, the best practice is to keep personalized content lean and use asynchronous loading for heavy personalization where possible so that the baseline site performance remains great.

Deployment, CI/CD, and Reliability

XP Deployments: In XP, deploying code or items could be stressful. Typically, you’d have maintenance windows for deploying new code, especially if it involved database changes. Content freezes often occurred during deployments to avoid conflicts. Some organizations achieved continuous deployment with XP via techniques like slot swaps if on Azure PaaS or by spinning up parallel environments, but it’s not trivial. Often, deployments incurred some downtime or at least required cache warming after, causing a slow response for a period. Also, a failed deployment could require rollback scripts, adding to the risk. DevOps for XP is doable, especially with containers and scripted pipelines introduced in later versions, but it’s a heavy application to deploy - a full XM/XP instance has many services (IDs, reporting DB, etc.) that all have to be in the correct state.

XM Cloud Deployments: XM Cloud was built with modern DevOps in mind. As mentioned, it supports Blue/Green deployment – you can deploy your new code to a staging slot while production keeps running, then switch traffic over when ready. This achieves zero downtime releases, a big win for marketing teams that demand high uptime. The deployment of content changes (like template changes or new items) is done via Sitecore Content Serialization and source control, which can be automated. Many XM Cloud users set up continuous integration such that any commit triggers a build and deploy to a test environment, etc. Sitecore’s built-in pipeline means you don’t have to script the entire release yourself - it will handle packaging the content and code. Additionally, since the front-end is separate, you often deploy that even more frequently, and those deploys are typically instantaneous to end-users because static files get versioned and are atomically published on CDNs.

Reliability: Outages can happen on any platform, but XM Cloud’s architecture and Sitecore’s SLA are geared to high availability. Your content authors work on an Editing host, which is separate from Edge delivery. If Edge were to have an issue, worst case, your site’s content API is down, Sitecore would work to restore it quickly under their SLA, but your editing might still be okay, or vice versa. In XP, if your server goes down, both editing and delivery could be offline unless you built redundancy. With XM Cloud, redundancy is built into the service (multiple instances, failovers, etc.). Also, backups are handled by Sitecore with geo-redundancy as mentioned. On XP, you have to ensure your backup/restore strategy is solid. Many XP incidents have been due to things like a deploy glitch or a missed config causing a site outage – those are less likely on XM Cloud, where infrastructure is consistent and deploys are tested via automation.

One factor is content delivery of XM Cloud is read-only from the perspective of content: authors publish to Edge, but end-users don’t change content on Edge. This separation of concerns increases reliability - the delivery endpoints aren’t doing heavy transactions or content writes, they are mostly serving cached data. XP content delivery sometimes had to handle things like writing personalization data or form submits into xDB, which could impact performance and reliability if xDB had issues. In XM Cloud, if you collect user data, it likely goes to an external system like a separate API or CDP, isolating any issues.

Monitoring and Debugging: With XP, you’d monitor via tools like Application Insights, custom logs, etc., in your own environment. With XM Cloud, Sitecore provides in-app logging and monitoring tools accessible from the portal. You can see logs of your CM instance easily. And for front-end, services like Vercel give real-time logs and metrics. So you get a good view of system health across the stack. Sitecore’s Ops team is also watching the infrastructure. This means you potentially catch issues faster, or Sitecore might alert you to anomalies. To contrast: on XP, if a search indexing service stopped, your team had to notice and fix it; on XM Cloud, if something in the managed service fails, Sitecore will be working to fix it often before you even notice, as part of their service reliability obligations.

Specific Optimization Techniques

To give concrete examples, here are some optimization strategies side-by-side:

  • Use of CDN: XP - use a CDN for media and set caching headers for static files; consider HTML caching for anonymous pages with short TTL. XM Cloud - CDN is inherent. Make sure to enable HTTP/2 or HTTP/3, and utilize image optimization on the front-end. Next.js has Image Optimization, which works great with Vercel’s CDN and leverages global edge caching for all content.

  • Caching strategy: XP – tune Sitecore’s output cache on renderings (e.g., cache renderings that don’t need to vary per user, use Sitecore’s cache clearing events on publish), increase item cache sizes for heavy traffic, maybe use a cache aside for expensive data (like results of a complex search query). Possibly pre-render some pages to static files if extreme performance is needed, as some have scripted Sitecore to output flat HTML for certain pages. XM Cloud - use Next.js incremental static regeneration for pages that can be cached, which automatically handles revalidating content after publish. Use Next’s API routes or middleware to handle any dynamic segments at Edge. If personalization rules are simple (by geolocation, login status), consider using edge middleware to modify responses on the fly without hitting the origin.

  • Scaling for peak: XP - pre-scale by adding CDs and enabling autoscale rules, warm up caches, maybe shorten cache expiration so content updates propagate, but be careful not to overload DB. XM Cloud - mostly auto. If expecting a viral spike, you could increase concurrency limits via Sitecore support or ensure the Edge is primed (perhaps pre-fetch or run a script to hit important pages so they’re cached globally). And ensure your front-end hosting plan supports concurrency. Enterprise tiers of Vercel handle massive concurrency, for example.

  • Database performance: XP - ensure SQL is on high-performance tier, maintain indexes, clean up analytics db to keep it slim if you don’t use historical data. Possibly offload analytics to xConnect Cloud or a data warehouse if needed. XM Cloud - the database is managed by Sitecore (in fact, Azure SQL). Not much you do directly, but since XM Cloud doesn’t accumulate interaction data by default, the DB load is mainly content reads/writes, which scale well. You still should organize content well (very large content trees can slow queries in either platform).

  • Personalization & Testing: XP - limit number of personalized components per page for performance, batch changes to profile scores to reduce overhead, use content profiling sparingly. Maybe run personalization rules on the CD server that has more resources, not on the edge, if you had multiple regions (with XP, if you deployed separate instances per region, each runs personalization independently). XM Cloud – take advantage of Sitecore Personalize’s ability to do heavy lifting outside the page request. For example, run segmentation nightly in CDP rather than computing on the fly. Use client-side experiment scripts for A/B tests, which utilize CDN edge networks to distribute variants quickly. Essentially, shift intensive personalization computations to pre-compute or client side, keeping the initial page load path as light as possible.

In terms of real-world outcomes, expect that an XM Cloud solution can achieve sub-second time-to-first-byte globally, very high throughput because most hits don’t touch the origin CMS, and handle usage spikes without breaking a sweat. In contrast, an XP solution might handle typical loads fine but needs careful babysitting to ensure similar metrics under duress, and often falls back to degraded mode (e.g., turning off personalization during high load, or relying on CDN cached pages that might not reflect the latest content if publishing frequently).

Cost of Optimization

It’s worth noting the cost implications of these performance strategies:

  • With XP, scaling up for performance means more servers or higher Azure bills. Idle capacity can cost you in slow periods. Also, high performance might demand a CDN subscription and possibly third-party monitoring tools, extra costs.

  • With XM Cloud, performance is largely built-in. You might pay a higher tier on Vercel for more edge function memory or a larger CDN usage, but you’re paying for actual usage (which corresponds with benefiting from that usage). The cost scales more directly with traffic. And you typically won’t need to invest in as much custom optimization labor. Development on Next.js is impressively fast compared to pure .NET development in terms of delivering features. That agility includes performance improvements - implementing a lazy-loading image or code-splitting in Next.js is straightforward and yields immediate performance gains, whereas optimizing an MVC site might involve more custom work.

Reliability and uptime are also part of performance. XM Cloud’s reliable deployment and infrastructure reduce the chance of outages from deployments. In XP, some teams schedule deployments at midnight Sunday and hope nothing goes wrong to avoid impacting users, as that is a performance consideration too. If you have to deploy during off-hours only, your ability to fix issues or update content quickly is hampered. XM Cloud’s zero-downtime deploys mean you can push improvements any time, which can be critical if there’s a high-priority content or code change.


9. Conclusion and Recommendations


Choosing between Sitecore XP and Sitecore XM Cloud in 2025 ultimately comes down to aligning the platform with your business priorities, technical requirements, and long-term digital strategy. Both options can deliver world-class digital experiences, but they do so in very different ways:

  • Sitecore XP offers full control, a rich integrated feature set, and proven capabilities as an all-in-one DXP – at the cost of higher maintenance, heavier infrastructure, and a more monolithic approach. It shines in scenarios where you need to retain data/control on-premises, or where you are leveraging all of its built-in marketing features under one roof. If you have an established XP solution that meets your needs and you can manage the upkeep and upcoming upgrades, XP remains a viable choice in the near term, especially given continued support until 2027+. Certain regulatory or localization needs may necessitate XP, for example, in China deployment or an isolated network. Just keep in mind that sticking with XP means accepting periodic upgrades and that new Sitecore innovations will be slower to reach you.

  • Sitecore XM Cloud represents the modern, cloud-first direction – reducing total cost of ownership through managed services, boosting agility with continuous updates, and enabling top-notch performance via headless architecture. It is best for organizations that want to focus on delivering content and customer experiences rather than managing servers. If you are starting fresh, XM Cloud is likely the better investment for the future. If you are on XP and finding that infrastructure and upgrades are eating into your budget or slowing you down, moving to XM Cloud can refocus your efforts on actual customer-facing improvements. For businesses that prioritize speed, scalability, and the ability to integrate best-of-breed services, XM Cloud is an excellent fit. It does require accepting a SaaS model and building up modern development skills, but the payoff is a more nimble digital platform.

When to choose XP:

  • You require a self-hosted environment for compliance or policy reasons that XM Cloud cannot meet, like specific in-country hosting or no external cloud allowed.

  • You extensively use XP’s multi-session personalization, marketing automation, and other xConnect-driven features, and transitioning those to composable alternatives is not feasible in the short term.

  • Your team and infrastructure are already optimized for XP, and the system is stable, with an upgrade to 10.4 planned and no major growth challenges – essentially, "if it isn’t broken" and you don’t urgently need what XM Cloud offers, you may continue with XP while planning for the longer-term future.

  • You need unlimited customization of the CMS core - for example, you have deep custom integrations that hook into Sitecore pipelines or data layers that would be hard to re-implement with XM Cloud’s constraints.

When to choose XM Cloud:

  • You want to minimize infrastructure and upgrade overhead – say you have a small IT team or want to reallocate your developers from maintenance to innovation. The automatic upgrades and managed hosting will benefit you greatly.

  • Site performance, global reach, and rapid deployment are top priorities – for instance, if your marketing team is pushing daily updates or campaign launches across regions, XM Cloud’s architecture will support that with fewer hiccups.

  • You are undertaking a major redesign or replatform anyway – an ideal time to switch to XM Cloud and build with the latest tech rather than refactoring an older XP solution.

  • Your digital strategy is “composable” – you might already be using or plan to use products like Sitecore Content Hub, Sitecore Personalize, or even non-Sitecore services. XM Cloud will integrate smoothly via APIs, whereas XP might feel comparatively siloed or require connectors.

  • You have a greenfield project and want to start on the right footing for the next 5-10 years. Adopting XM Cloud ensures the platform itself won’t become outdated in that period, and you’ll get continuous improvements.

A balanced, experience-driven perspective: Many seasoned Sitecore architects or Sitecore MVPs like myself advise evaluating how much "platform" you really need. In the past, some chose XP for safety since it had everything out of the box, but ended up not using half of it. With budgets tighter and digital experience needs evolving faster, it often makes sense to choose a leaner, more flexible setup, which is XM Cloud plus only the additional services you truly need. As one real-world consideration, if you can count the number of XP features you actively use on one hand, it’s a strong signal that XM Cloud or even XM on-prem would be more cost-effective. Sitecore itself notes that without xConnect, XM has a smaller footprint and TCO than XP. That logic extends to XM Cloud, which is essentially XM plus the SaaS benefits.

On the other hand, if your organization has squeezed substantial value from XP’s integrated suite – say you have marketing teams running automated campaigns and personalization that directly drive revenue – then you shouldn’t jump off XP until you’re confident you can reproduce or enhance that capability in the new model. It might mean a phase where you introduce Sitecore CDP/Personalize alongside XP (that is possible) to gradually transition without losing functionality.

Prepare for change: If you do decide to move to XM Cloud, approach it methodically. Plan the migration or build with a clear scope, engage experienced Sitecore partners or experts who have done it, and consider doing a pilot or proof-of-concept first. This will surface any challenges early (like missing features or integration points) and allow your team to learn XM Cloud’s nuances. Also, budget for the learning curve – maybe get training for your developers on Next.js and Sitecore Headless. The good news is that many have done this before, and the community has produced guidance and tools such as scripts to migrate content or patterns to implement common XP features in XM Cloud. Leverage those resources to avoid reinventing the wheel.

Final thought: The direction of the market is clear - cloud-native, composable DXP is the future, and Sitecore XM Cloud is a centerpiece of that strategy. However, Sitecore acknowledges that each customer’s journey is unique. They are supporting XP for years to come precisely because they know a forced march to the cloud is not feasible for everyone overnight. So, evaluate your own readiness and needs. You might choose to run XP and XM Cloud in parallel for a time, or move fully to XM Cloud now, or stay on XP a bit longer, but with a roadmap to evolve. What’s important is to make an informed, conscious choice rather than simply defaulting to one or the other. Hopefully, this guide has illuminated the concrete differences in costs, effort, capabilities, and optimizations so you can make that choice with clarity.

No matter which path you choose, success will hinge on execution: an optimally tuned XP can still deliver excellent experiences, and a poorly implemented XM Cloud site could underwhelm. The platform is an enabler, but the vision and strategy you apply are what create standout digital experiences. Align the choice to your strategy: if agility, scalability, and continuous improvement are paramount, XM Cloud aligns well; if complete control and one-stop capabilities are paramount, XP can still serve. Either way, ensure you have the right skills and partners to get the most out of the platform.

In closing, for most organizations in 2025, Sitecore XM Cloud will be the logical choice moving forward, with Sitecore XP remaining a reliable but eventually legacy option. Adopting XM Cloud sets you on a course to leverage Sitecore’s evolving innovations without the operational drag – an appealing proposition for those looking to accelerate their digital maturity. Evaluate carefully, plan thoughtfully, and you’ll make the choice that best empowers your digital experience goals.

XM Cloud Headless Endpoints - Local vs Cloud vs Preview

XM Cloud is a purely headless CMS, so your front-end app (say, a Next.js site) calls Sitecore APIs for the layout and content rather than having on spot, similarly to what traditional monolith CMS page requests did:

At the same time, this approach brings a variety of ways that content+layout could be consumed, depending on which particular endpoint is being used and the mode it serves. I wrote this post to explain the options and differences between them.

GraphQL Endpoint Working on a Local CM in Docker containers

When you run your app locally with Docker containers, all content calls go straight to your local CM instance. For example, a Next.js app using JSS or Cloud SDK might fetch layout or GraphQL data from the local CM at endpoints like:

  • /sitecore/api/graph/edge (the GraphQL Preview API on the local CM)

  • /sitecore/api/authoring/graphql/ide (the URL of GraphQL Playground IDE on the local CM for querying)

In other words, your locally running headless app pulls content directly from the local Sitecore CM, including any unpublished edits. You’ll usually develop this way to see live changes immediately. Notably to say, there is no mock/substitute of Experience Edge with local Docker containers, which means you only have a preview endpoint with local container-based development.

Cloud Delivery API

The Delivery API for each of the cloud environments has two modes: Preview, which runs on the CM itself, and Live from Experience Edge. Once content is published from any XM Cloud environment, it lands on Experience Edge for that environment – the cloud GraphQL delivery service. In practice:

  • Preview API: Every XM Cloud environment (dev, QA, etc.) has a preview GraphQL endpoint on its CM, at */sitecore/api/graph/edge. Content fetched here includes unpublished draft changes. Editors use this to see a work-in-progress.

  • Live API: The live GraphQL endpoint is on Experience Edge service at https://edge.sitecorecloud.io/api/graphql/v1​. This serves only published content – essentially a read-only high-performance delivery API.

In other words, no publish = no live content. If you never publish your edits, the live API returns nothing (or only older content, if pre-exists), because Edge only knows what’s been pushed from the related CM.

Key differences:

  • Endpoint paths: Preview GraphQL is /sitecore/api/graph/edge while Live Edge GraphQL operates at /api/graphql/v1.

  • Publishing impact: Only published items show up on the live API.

  • Managing content through APIs: it is important to mention that Authoring and Management API relates only to the CM and cannot be applied to Experience Edge directly.
  • Authentication key: preview environments rely on API Key for authentication, while Live requires Experience Edge Token. I explain this below:

When your headless app connects to a Preview endpoint (/sitecore/api/graph/edge) on your local Docker CM or cloud CM for Dev/QA/Prod, it must send an API Key for authentication. API Key is effectively an ID of an item located under /sitecore/system/Settings/Services/API Keys folder

When your headless app connects to the Live Delivery API (/api/graphql/v1) on Experience Edge, it must instead authenticate with an Experience Edge Token. Edge tokens are environment-specific. Without a proper Edge Token for a given particular environment, the /api/graphql/v1 endpoint will reject requests.

This table illustrates what

Scenario Endpoint Auth Type Header
Local CM /sitecore/api/graph/edge API Key ID sc_apikey: <api-key-id>
Cloud CM (Dev/QA/Prod) /sitecore/api/graph/edge API Key ID sc_apikey: <api-key-id>
Experience Edge (Live) /api/graphql/v1 Experience Edge Token Authorization: Bearer <edge-token>

One of the easiest ways to reach out to specific environmental access keys is through the Deploy App:


Setting up multiple preview environments

If you want multiple preview environments for dev, QA and prod, you’ll need separate deployments of your front-end. Essentially, each environment needs two “versions” of your headless app: one pointing at the CM in preview mode and one pointing to the content published to Edge (live mode). For example, in a project with 3 environments (Prod, QA, Dev), this could mean:

  • Dev-Live (queries Edge)

  • Dev-Preview (queries Dev CM)

  • QA-Live

  • QA-Preview

  • Prod-Live

  • Prod-Preview

That’s up to 6 different sites running your headless app: 3 envs × 2 modes. Each one has different environment variables/URLs. It sounds like a lot, but it's pretty easy and quick to configure and lets each team see exactly what they need.

Hope this post explains how different modes and environments operate well together.

XM Cloud: Beyond the Serialization

Distinguish Between Definition and Content Items

In XM Cloud, serialization is primarily a developer/ops concern, not a task for content authors. Developers and DevOps engineers use the Sitecore CLI to manage definition items (templates, layouts, SXA settings, etc.) in version control, whereas content authors continue to work in the Content Editor/Experience Editor and publish content via the usual publishing pipeline.  In contrast, content authors simply publish content; they shouldn’t be expected to run CLI commands: we reserve the CLI workflow for dev-defined items, and let content authors handle content via Sitecore’s authoring tools.

In XM Cloud, all templates and configurations are the definition items in the Sitecore tree - many of these are delivered as items-as-resources in protobuff resource files. By default, XM Cloud provides a base set of definition items in resource packages; custom definitions (such as your templates, renderings, layouts, SXA component definitions) should be added via serialization. The CLI can push/pull any item in the tree, so treat your custom definitions like any other serialized item. For example, you would include custom layouts (under /sitecore/Layout/Layouts/YourTenant), rendering definitions (/sitecore/Layout/Renderings/YourTenant), SXA rendering variants, themes, and placeholder settings in your modules. In fact, the Sitecore docs note that SCS modules allow you to "organize and separate serialized items according to their purpose".

You generally do not manually transfer definitions by hand; instead, you define them in your project and let the CLI handle serialization. As a special tool, Sitecore provides an Items as Resources CLI plugin (dotnet sitecore itemres) to package definition items into *.DAT resource files, but in most cases, you simply let sitecore ser push pack the YAML and deploy it to XM Cloud.

Note, that some environment-level settings are not items. For example, custom Sitecore security domains live in a config file on the server, not in the content tree, so they cannot be serialized or deployed via CLI. In those cases, you must handle them outside of SCS.

In summary: treat definition items as code: include them in your serialization modules and commit them, and let the Sitecore CLI bundle them into the XM Cloud resource IAR package. Content items, by contrast, should be managed by content workflows.

Content Serialization

Generally, don’t serialize day-to-day content. XM Cloud follows the old wisdom of treating content differently from code: the CLI is not intended as a general content migration tool. Instead, content authors create or edit content items in the CM interface or Pages Builder and then publish them to delivery targets. Serializing content will lead to conflicts and source-control bloat.

That said, there are a few exceptions where you might include minimal content stubs or settings in serialization. For example, it’s common to serialize the homepage item itself so that a brand-new environment has the correct site entry point immediately upon first serialization. You'd want to explicitly include the tenant and site root with CreateAndUpdate operations - this ensures that new environments get a placeholder homepage item (and updates propagate), without overwriting content. You might also serialize certain settings or dictionary items that are truly "configuration" (say, a language items folder or a set of shared data templates). But actual content (articles, product entries, news items) should be kept out of serialization.

In practice, restrict content serialization to very small, static subsets (often at most the single site-root node) and mark them as create-only or create-and-update. For example:

{
  "name" : "TenantA_SiteRoot",
  "path" : "/sitecore/content/TenantA/SiteA,"
  "scope": "singleItem",
  "allowedPushOperations" : "CreateUpdateAndDelete"
}

This would ensure the /SiteA item exists in all environments, but leave its children alone. The rest of /sitecore/content/TenantA/SiteA descendants (actual page content) would not be included.

Remember that after you push any content items, you still must publish them to make them live. The ser push command only writes into the CM database; it does not publish to Experience Edge. To serve content, you must run a publish command (dotnet sitecore publish --target Edge).

Summarizing: Limit content serialization to definition items with some exceptions like an empty homepage or settings, and let normal publishing handle real content.

Also, "do not include vanilla XM Cloud items – include only custom-created items". Content changes by authors should flow through Sitecore’s normal publishing workflows, not through SCS commits.

Serialization Scopes

Sitecore CLI modules use scopes to control how deeply an include or rule applies. The scope property can be one of:

  • SingleItem – only the specified item itself (no children).

  • ItemAndChildren – the item plus its immediate (one-level) children.

  • ItemAndDescendants – the item and all levels of descendants - the full subtree. That is a default value.

  • DescendantsOnly – all descendants of the item, but not the item itself.

  • Ignored – skips this branch entirely, used in rules to exclude subtrees.

For example, suppose you include a path /sitecore/content/TenantA/SiteA in a module. If not specified, that is ItemAndDescendants by default, so it would pull the entire site tree. If you want only the root item and none of its children, you would add a rule with "scope": "SingleItem". Conversely, to skip an unwanted subfolder, you could use "scope": "Ignored" on that path.

A concrete example of a rules section might look like:

"items": {
  "includes": [
    {
      "name": "SiteA",
      "path": "/sitecore/content/TenantA/SiteA",
      "allowedPushOperations": "CreateUpdateAndDelete",
      "rules": [
        { "path": "/sitecore/content/TenantA/SiteA/Data", "scope": "Ignored" },
        { "path": "/sitecore/content/TenantA/SiteA/Home", "scope": "Ignored" },
      ]
    }
  ]

This says "include the SiteA item (with all descendants by default) but ignore the entire Data and home Page subfolders." In practice, you’ll define scopes to precisely include what you need: broad (ItemAndDescendants) for full branches, and narrow (SingleItem or Ignored) to exclude or limit depth.

Serialization Order and Modules

Since you organize your serialized items into modules within each .module.json file in the Sitecore CLI, you must somehow define which modules depend on stuff from others. This each module can have an optional references list to other modules. The CLI uses these references to enforce a load order. For example, if you have a Foundation module with templates (Foundation.CoreTemplates) and a Feature module that depends on them (Feature.Shop), you would write:

{
  "namespace": "Feature.Shop",
  "references": [ "Foundation.CoreTemplates" ],
  "items": {
    "includes": [
      { "name": "ProductTemplates", "path": "/sitecore/templates/Feature/Shop", "allowedPushOperations": "CreateUpdateAndDelete" }
      // ...
    ]
  }
}

By specifying "references": [ "Foundation.CoreTemplates" ], you ensure the CLI pushes/pulls Foundation templates first, then the shop items. Wildcards are allowed ( "Foundation.*") to reference all Foundation modules. If you omit references, the CLI may process modules in alphabetical or file order, which can lead to missing-dependency errors, such as pushing a rendering before its template exists.

In practice, follow Helix conventions: have a base module for core templates/branch templates, then project-level modules that reference it and use the references array in each module to declare dependencies.

Alternatively, you can also tag modules in CLI commands (with -i) to run only subsets, but the fundamental sequencing comes from references. If dependencies are missing or misordered, you will see errors during push (like “item not found” or unresolved references). Always review dotnet sitecore ser info to verify your module graph.

SXA Serialization Considerations

When using SXA in XM Cloud, treat SXA definition items as code. As usual, you should serialize your SXA component definitions and site structure, but not your actual content. Key SXA assets to include are:

  • Rendering Variants and Templates: Anything under /sitecore/layout/Rendering Variants/... and the SXA Page/Partial designs under /sitecore/layout/Layouts/... or /sitecore/content/TenantName/SiteA/Presentation/....

  • Placeholder Settings and Layouts: SXA uses placeholders and page layouts, which live under /sitecore/Layout or under the site; include those as part of layouts and placeholders sections.

  • Themes and Styles: If your SXA site uses a custom theme (under /sitecore/media library/Themes or the SXA Theme item), serialize that.

  • SXA Site Settings: Under each site (e.g. /sitecore/content/Tenant/SiteA/Settings), include any site-level settings items that define colors, etc., if they are required for deployment.

  • Site Templates: SXA allows site templates in the dashboard; if you have custom site templates, serialize those under /sitecore/templates/Project/....

Do not serialize authored page content (articles, products, etc.) from SXA sites. Also consider shared vs. site-specific: if multiple sites under one tenant share variants or partial designs, put them in a shared module (under the tenant node). If a design is only for SiteA, put it under the SiteA module. In general, follow the same include rules as above, putting SXA assets under your project/feature paths. For example, include renderings and placeholder settings under /sitecore/Layout/Renderings/Project/... and /sitecore/Layout/Placeholder Settings/Project/... - these would cover your custom SXA renderings and placeholder definitions as well. By version-controlling SXA assets in the CLI, you ensure that your site designs, variants and styles are consistent across environments, while leaving content (pages and datasources) to the content pipeline.

Module Organization

For the multisite and especially multi-tenant data architecture, it becomes crucial to organize your modules and serialization in a totally isolated way. Thus, everything becomes self-contained so that removing one site/ tenant folder does not affect the rest of the serialized assets. To achieve that, I would recommend doing this:

  • Organize all the assets under a specific folder, for example: authoring/items/client
  • All the relevant modules fall into this folder. I usually split them into three groups: client.global.module.json; client.components.module.json and client.site.module.json
  • Each of these module files must include a path directive, which effectively defines a subfolders structure: "path": "components" or "path": "site". This is the most crucial bit.
  • Nothing else exists immediately under authoring\items folder other than clients and areas; typically there would be a global folder followed by client1, client2, etc.

I would also recommend reading this article, which I found to be helpful. Hope you find these tips helpful!