---
title: Upgrade to CMS 13 from CMS 12
slug: cms-13/docs/upgrade-to-cms-13
docTags: 
createdAt: 2026-07-30T20:22:07.530Z
---

Upgrade your Optimizely CMS solution from CMS 12 to CMS 13. This article covers the migration strategy, including AI-powered tools that streamline modernization.

For details about CMS 13 platform changes and upgrade considerations, see [CMS 13 breaking changes](docId\:byC7COq00R-mLmWVV9_eE).

:::hint{type="warning"}
**Important**
CMS 13 runs on .NET 10 and newer. When upgrading from earlier CMS versions, ensure that your solution targets the required .NET version before beginning the migration.

Previous migration tools for Optimizely CMS have been deprecated. Microsoft recommends using GitHub Copilot or similar AI-assisted development tools to help modernize and update your codebase during the upgrade process.
:::

## Review mandatory components for CMS 13

Before starting, review [Overview of CMS 13](docId\:yjXw56Ns6VLi1FCjqw12V) to understand the mandatory and optional components of CMS 13. You should consider the timelines needed for each component in your go-live planning.

## Use GitHub Copilot for AI-assisted modernization

The GitHub Copilot app modernization chat agent provides the following advantages during CMS upgrades:

- **Accelerated development** – Automates repetitive coding tasks and suggests solutions for common migration challenges.
- **Reduced error rates** – Helps identify potential issues and provides correct syntax or API usage.
- **Knowledge transfer** – Acts as an intelligent assistant, providing context-aware suggestions for new frameworks and libraries.
- **Efficiency** – Speeds up the overall migration timeline, allowing teams to focus on higher-value tasks.

For instructions on using GitHub Copilot, see the Microsoft and [GitHub documentation](https://github.com/features/copilot). Test thoroughly after migration to verify the stability and functionality of your solution.

## Upgrade to CMS 13

CMS 13 builds on the CMS 12 .NET foundation but introduces changes to service registration, API surfaces, and the site management model.

## Prerequisites

- **Existing CMS 12 solution** – Your application should already be running on Optimizely CMS 12.
- **.NET 10 SDK** – CMS 13 requires .NET 10. Packages will fail `dotnet restore` on earlier .NET versions.
- **Database backup** – Create a full backup of your CMS database before starting.
- **IDE** – Visual Studio 2026 (18.0+) or a compatible IDE with .NET 10 support.

## Pre-upgrade: Audit and prepare

Before changing any packages or code, audit your solution for potential compatibility issues.

:::hint{type="danger"}
**Warning**
Search & Navigation (`EpiServer.Find`) is not supported in CMS 13. Refer to [Migrate from Search & Navigation to Optimizely Graph](docId\:sNcLLcLYgWv_QVb0Mtqus) to replace the legacy content indexing, preview, and delivery pipeline. Implement search with Optimizely Graph or use your own search provider.
:::

- **Inventory third-party packages** – Check each non-Optimizely NuGet package for a CMS 13-compatible version. Remove or disable incompatible packages *before* upgrading Optimizely packages. See [Optimizely and third-party packages breaking changes](docId\:Ed8WEWza1QlgYfuLIsRg_) for a list of commonly used packages and their compatibility.
- **Document customizations** – Note any custom scheduled jobs, custom content types, initialization modules, and integration points that may need updates.
- **Resolve all obsolete warnings** – CMS 13 removes APIs marked as `[Obsolete]` in CMS 12. Before upgrading, resolve all obsolete warnings in your CMS 12 build. Enable `<TreatWarningsAsErrors>true</TreatWarningsAsErrors>` in your `.csproj` file to catch these early. Any unresolved obsolete usage becomes a compilation error after upgrading.
- **Review Optimizely Graph queries** – The Optimizely Graph schema in CMS 13 contains breaking changes compared to CMS 12. Frontend applications that query Graph will require updates to reflect the new schema. Review your Graph queries and update them before going live.
- **Review Conventions API changes** – If you use the Conventions API to customize content indexing (computed fields, type exclusions, or indexing types), review the [Conventions API migration guide](docId\:oCt_aukEgQzz4ZODGSsc1) for feature-by-feature migration instructions.

:::hint{type="info"}
**Important**
**Migrate DAM from CMS 12**
If you use DAM with CMS 12, migrate your DAM asset references after the upgrade with the **Optimizely DAM Legacy Asset Migration** scheduled job, available in CMS 13.3.0 and later. See [Migrate DAM from CMS 12 to CMS 13](https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/migrate-dam-from-cms-12-to-cms-13).

**Third-party package compatibility**
Third-party package incompatibility is the single largest area of effort during a CMS 13 upgrade. Packages such as `Geta.NotFoundHandler.Optimizely`, `Geta.Optimizely.Sitemaps`, `Geta.Optimizely.GenericLinks`, `Geta.Optimizely.ContentTypeIcons`, and `Advanced.CMS.AdvancedReviews` may not yet have CMS 13-compatible versions. Removing these packages can cause cascading effects, including lost transitive dependencies and orphaned content types in the database. Plan for this work before you begin.

**Removed features**
**Dynamic Properties**, **Mirroring**, and the legacy **Plugin system** were deprecated in CMS 12 and are fully removed in CMS 13. All related classes, interfaces, stored procedures, and database tables have been removed, including export/import APIs tied to these features. Search your codebase for references to the `EPiServer.Core.DynamicProperty*`, `EPiServer.PlugIn`, and mirroring-related transfer types, and remove or replace them before upgrading. See [Breaking changes in CMS 13](docId\:byC7COq00R-mLmWVV9_eE) for details.
:::

## Update target framework

Update your `.csproj` file to target .NET 10:

```xml
<PropertyGroup>
  <TargetFramework>net10.0</TargetFramework>
</PropertyGroup>
```

If you use Docker, update your base images to .NET 10.

:::hint{type="warning"}
**Important**
After changing the target framework to `net10.0`, your solution does not compile until you update the NuGet packages in the next step. This is expected. Do not attempt to build at this point.
:::

## Update NuGet packages

Update all `EPiServer.*` and `Optimizely.*` packages to their CMS 13 versions:

```xml
<PackageReference Include="EPiServer.CMS.UI.AspNetIdentity" Version="13.0.0" />
<PackageReference Include="EPiServer.Cms.UI.VisitorGroups" Version="13.0.0" />
```

After updating, run `dotnet restore` to verify all packages resolve correctly.

```shell
dotnet restore
```

A successful restore completes with no errors:

```javascript
Restore completed in 2.3s for MyProject.csproj.
```

### Common issues at this stage

| Error                                                               | Cause                                        | Resolution                                                                                                                                       |
| ------------------------------------------------------------------- | -------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `NU1202: Package X is not compatible with net10.0`                  | Third-party package does not support .NET 10 | Remove the package or find a CMS 13-compatible version. See [Optimizely and third-party package breaking changes](docId\:Ed8WEWza1QlgYfuLIsRg_). |
| `NU1608: Detected package version outside of dependency constraint` | Version conflict between Optimizely packages | Ensure all `EPiServer.*` and `Optimizely.*` packages target the same CMS 13 version (for example, `13.0.0`).                                     |
| Missing type errors after removing packages                         | Lost transitive dependencies                 | Explicitly add the missing package (for example, `Newtonsoft.Json`).                                                                             |

If `dotnet restore` succeeds but `dotnet build` produces errors, proceed to the [Fix API breaking changes](docId:1Y3KoWaxY0cxXGcXMbXK8) section. Compilation errors from API changes are expected at this stage and are addressed there.

:::hint{type="info"}
**Note**
Removing packages like `EPiServer.Find` can cause you to lose transitive dependencies your code relies on, such as `Newtonsoft.Json`. If you encounter missing type errors after package cleanup, explicitly add the required package or migrate to `System.Text.Json`.
:::

## Update service registration

The service registration methods require the `EPiServer.DependencyInjection` namespace (not `Microsoft.Extensions.DependencyInjection`).

If your CMS 12 solution already uses `AddCms()`, this call continues to work in CMS 13 and is the recommended approach:

```csharp
services.AddCms();
```

Internally, `AddCms()` registers the following services:

```csharp
services
    .AddCmsHost()
    .AddCmsCore()
    .AddCmsHtmlHelpers()
    .AddCmsTagHelpers()
    .AddCmsUI()
    .AddAdmin()
    .AddTinyMce()
    .AddCmsImageSharpImageLibrary()
    .AddOptimizelyCmsServicev1()
    .AddOAuthEndpoints()
```

### Granular service registration

If your CMS 12 solution uses granular service registrations instead of `AddCms()`, review the list above and add any registrations your solution is missing.

The following packages have been removed as core dependencies from `EPiServer.CMS` in CMS 13. If your solution uses them, ensure they are explicitly referenced in your `.csproj` file and their services are registered:

- `EPiServer.CMS.UI.AspNetIdentity` – Register with `AddCmsAspNetIdentity<ApplicationUser>()`.
  Keep this registration if ASP.NET Identity authenticates site visitors, even when Opti ID is enabled. Remove it only if ASP.NET Identity was used solely for editor and administrator sign-in.
- `EPiServer.Cms.UI.VisitorGroups` – Register with both `AddVisitorGroupsMvc()` and `AddVisitorGroupsUI()`.

The following example shows a complete CMS 13 service registration including optional packages:

```csharp
services
    .AddCmsAspNetIdentity<ApplicationUser>()
    .AddCms()
    .AddVisitorGroupsMvc()
    .AddVisitorGroupsUI();
```

:::hint{type="info"}
**Important**
CMS 13 uses assembly scanning to discover referenced packages at startup. Every NuGet package your project references must either have its services explicitly registered (for example, `AddTinyMce()` for the TinyMCE editor) or be completely removed from your project. If a package is referenced but not registered, the application will fail at startup.
:::

CMS 13 requires the SQL Server database compatibility level to be 140 or higher. If you have an older on-premises database, enable automatic compatibility level updates in your `Startup.cs`:

```csharp
services.Configure<DataAccessOptions>(options =>
{
    options.UpdateDatabaseCompatibilityLevel = true;
});
```

### Verify service registration

After updating service registrations, run `dotnet build` to verify the configuration compiles. The build may produce errors from API breaking changes (addressed in the following sections), but service registration issues produce distinct errors:

- `'IServiceCollection' does not contain a definition for 'AddCmsCore'` – Add `using EPiServer.DependencyInjection;` (not `Microsoft.Extensions.DependencyInjection`).
- **Startup crash:** `No service for type 'X' has been registered` – A referenced package is missing its `Add*()` registration. Identify the package from the type name and add the corresponding registration, or remove the package entirely.
- **Startup crash:** `Unable to find a module by assembly 'X'` – A removed package still has references in your project. Search for and remove all `using` statements and service registrations that reference it.

## Enable Content Manager and Optimizely Graph

:::hint{type="warning"}
**Important**
If you are already using Optimizely Graph with CMS 12, *before* enabling Content Manager, complete the following:

1. [Enable Graph](docId\:GHPdKRxNshVI1_ghsWOXf)for your project.
2. Review the [Graph schema comparison between CMS 12 and CMS 13](docId:8sNTSprunXEsHeqbYcMzk).
3. [Migrate your Graph project to CMS 13](docId:5IIpWhRi9sd4hvXlqyaHY) .
4. Update your code to the CMS 13 schema.
:::

Content Manager and Optimizely Graph are not enabled by default in CMS 13 and require explicit opt-in. Graph is mandatory to use the full capabilities of CMS 13 (see [Overview of CMS 13](docId\:yjXw56Ns6VLi1FCjqw12V)). The following CMS 13 features depend on Graph infrastructure:

- [Optimizely Agent Platform](docId\:rHBhJmLiQvmx9789rso0n) – Graph enables Mark to index, interpret, and act on your content.
- [Content Manager](docId\:G_PIvJxyC84ET38KrOsN0) – The editorial experience relies on Graph for content discoverability.
- [External content](docId\:JAfHZxileO8PvesaA0pBe) – Requires Graph indexing capabilities to connect external sources like DAM systems, PIMs, or other third-party applications, set up mappings, and manage content types to enable seamless access to external content.
- [Content binding](docId:2z5gDZJDOJjeVBaGn5xji) – Uses Graph structured queries to connect content items to external data sources or other content items. It enables automatic synchronization and structured relationships between content items.

:::hint{type="info"}
**Note**
Before adding the Graph NuGet package, you must [enable the Graph service](docId\:GHPdKRxNshVI1_ghsWOXf) within the PaaS portal.
:::

To add the NuGet packages, add the following to your `.csproj` file:

```xml
<PackageReference Include="Optimizely.Graph.Cms" Version="13.0.0" />
<PackageReference Include="EPiServer.Cms.UI.ContentManager" Version="13.0.0" />
```

Or run the following commands:

```shell
dotnet add package Optimizely.Graph.Cms
dotnet add package EPiServer.Cms.UI.ContentManager
```

To register the services, add the following to your `Startup.cs` :

```csharp
services.AddContentGraph();
services.AddContentManager();
```

:::hint{type="danger"}
**Warning**
Register `AddContentGraph()` before `AddContentManager()` because Content Manager depends on Graph infrastructure. Reversing the order causes startup failures.
:::

Adopt Graph at the beginning of your project. Adding Graph to an existing CMS 13 solution requires more effort than including it during initial setup.

See [Get Started with Optimizely Graph for CMS 13](docId\:NdJElDTXVkJewypNvKVqZ) to configure Graph.

## Fix API breaking changes

After updating packages, run `dotnet build` to surface compilation errors from API changes. Address these errors in any order because they are independent of each other. Continue fixing errors and rebuilding until `dotnet build` completes with zero errors.

The most common changes are listed below. For a complete list, see the [CMS 13 breaking changes](docId\:byC7COq00R-mLmWVV9_eE) documentation and the [API replacement map](docId\:emx27QfVaTI6ZUfLp2GCH) for a quick-reference lookup table.

### SiteDefinition replaced by Application model

`ISiteDefinitionResolver` is replaced by `IApplicationResolver` in the `EPiServer.Applications` namespace. For code that used `SiteDefinition.Current.RootPage`, use `ContentReference.RootPage` instead.

```csharp
// Before (CMS 12)
using EPiServer.Web;

public class MyController: Controller {
  private readonly ISiteDefinitionResolver _siteResolver;

  public MyController(ISiteDefinitionResolver siteResolver) {
    _siteResolver = siteResolver;
  }
}

// After (CMS 13)
using EPiServer.Applications;

public class MyController: Controller {
  private readonly IApplicationResolver _applicationResolver;

  public MyController(IApplicationResolver applicationResolver) {
    _applicationResolver = applicationResolver;
  }
}
```

### Start page resolution simplified

Replace `IApplicationResolver.GetByContext()` calls that retrieve the start page with `ContentReference.StartPage`:

```csharp
// Before (CMS 12 / early CMS 13 previews)
var website = _applicationResolver.GetByContext() as Website;
var startPageContentLink = website?.RoutingEntryPoint;

// After (CMS 13)
var startPageContentLink = ContentReference.StartPage;
```

The `IRoutableApplication.EntryPoint` property remains available for advanced scenarios that require explicit application context.

### PageReference replaced by ContentReference

Replace all uses of `PageReference` with `ContentReference` and `.PageLink` with `.ContentLink`:

```csharp
// Before (CMS 12)
PageReference pageRef = currentPage.PageLink;

// After (CMS 13)
ContentReference contentRef = currentPage.ContentLink;
```

### ContentArea.FilteredItems removed

`ContentArea.FilteredItems` is removed. Use `ContentArea.Items` instead:

```csharp
// Before (CMS 12)
var items = myContentArea.FilteredItems;

// After (CMS 13)
var items = myContentArea.Items;
```

:::hint{type="info"}
**Note**
`ContentArea.Items` may have different filtering behavior than the previous `FilteredItems` property. Test content area rendering thoroughly after this change.
:::

### IContentTypeRepository no longer generic

Remove the generic type argument:

```csharp
// Before (CMS 12)
IContentTypeRepository<ContentType> repo;

// After (CMS 13)
IContentTypeRepository repo;
```

### Service locator pattern replaced by dependency injection

Replace `ServiceLocator` and `Locate.Advanced` patterns with constructor injection:

```csharp
// IInitializableModule before (CMS 12)
var loader = context.Locate.Advanced.GetInstance < IContentLoader > ();

// IInitializableModule after (CMS 13)
var loader = context.Services.GetRequiredService < IContentLoader > ();

// Service before (CMS 12)
public class MyClass {
  public MyClass() {
    var contentLoader = ServiceLocator.Current.GetInstance < IContentLoader > ();
  }
}

// Service after (CMS 13)
public class MyClass {
  private readonly IContentLoader _contentLoader;

  public MyClass(IContentLoader contentLoader) {
    _contentLoader = contentLoader;
  }
}
```

### Additional breaking changes

Fix these to avoid compilation errors.

| CMS 12                            | CMS 13                                               | Notes                      |
| --------------------------------- | ---------------------------------------------------- | -------------------------- |
| `InitializationEngine.Assemblies` | `AppDomain.CurrentDomain.GetAssemblies()`            | Assembly discovery changed |
| Platform navigation HtmlHelpers   | TagHelpers (for example, `<epi-navigation-primary>`) | UI helper migration        |

### Deprecation warnings

The following APIs are deprecated in CMS 13 and produce `[Obsolete]` compiler warnings. They continue to work in CMS 13 but are planned for removal in a future major version. Track these for future cleanup.

| CMS 12/13 API                           | Status                                 | Action                                                   |
| --------------------------------------- | -------------------------------------- | -------------------------------------------------------- |
| `PropertyDefinitionTypePlugInAttribute` | Deprecated (planned removal in CMS 14) | Suppress warning for now; plan replacement before CMS 14 |
| `IPageRouteHelper`                      | Deprecated (planned removal in CMS 14) | Suppress warning for now; plan replacement before CMS 14 |

## Check for build errors

Run `dotnet build`. When the build completes with *zero errors*, you have resolved all blocking API breaking changes. Remaining `[Obsolete]` warnings are non-blocking and can be addressed after the upgrade is stable.

:::hint{type="info"}
**Note**
If you still have errors, check the [API replacement map](docId\:emx27QfVaTI6ZUfLp2GCH) for the specific type or method name. For errors not covered in this guide or the replacement map, consult the detailed [breaking changes by topic](docId\:byC7COq00R-mLmWVV9_eE) articles.
:::

## Update admin URL references

The CMS admin path has changed from `/EPiServer`. The new path depends on your authentication setup:

- **DXP-hosted with Opti ID** – The default path is `/ui/CMS`.
- **Self-hosted (without Opti ID)** – The default path is `/Optimizely/CMS`.

Update any bookmarks, internal documentation, health checks, or hardcoded URL references in your codebase.

## Configure the application model

CMS 13 replaces the **sites** concept with **applications**. The database migration automatically converts your existing site configuration into an **In process** application. After building and running your upgraded site for the first time, go to **Settings > Applications** in the CMS **Admin** interface and verify the migrated **Application** settings, including the start page and hostname.

Two application types are available:

- **In process** – The default application type assigned to migrated sites to support backwards compatibility.
- **Headless** – Provides stronger support for headless CMS scenarios with these key characteristics:
  - Renders actual content in a separate application (such as Next.js, React, or Vue).
  - Delivers CMS content using Optimizely Graph.
  - Supports preview tokens for secure preview functionality.

See [Application framework](docId\:woUIJII7WGJFp3ZrEuS7M) for more details.

### Switch to the Headless application type

To switch your migrated application type from **In process** to **Headless**, complete the following steps:

1. Go to **Settings > Applications** in the CMS admin interface.
2. Delete the default **In process** application that the database migration creates.
3. Create a **Headless** application.
4. Set your start page as the application entry point.
5. In the **Hosts** section, add your hostname as the default host.

## Database and data considerations

The CMS 13 database migration runs automatically on first startup, but the following issues can occur:

- **Schema migration failures** – The schema migration may fail with SQL Error 1913 due to conflicting indexes. If this happens, manually drop the conflicting indexes identified in the error message, then restart the application to let the migration continue.
- **Tab name validation** – CMS 13 enforces alphanumeric-only identifiers for tab names (no spaces or special characters). If your content types use tab names like **SEO Settings**, change the identifier to an alphanumeric value and use the `[Display(Name = "SEO Settings")]` attribute for the display label.

## Test and stabilize

After the code migration, complete the following verification steps:

1. Resolve all compilation errors and review compiler warnings, which indicate further changes may be needed.
2. Start the application and check the console output for startup exceptions or runtime errors.
3. Confirm the CMS admin interface loads at `/ui/CMS` (or `/Optimizely/CMS` if self-hosting without Opti ID).
4. Create, edit, preview, and publish content to verify the editorial experience works end to end.
5. Verify pages render correctly, including content areas, blocks, and media.
6. Check for `[Obsolete]` deprecation warnings in the build output. These are non-blocking but should be tracked for future cleanup before CMS 14.

## Troubleshooting

- **"No policy found" errors in the admin UI** – A removed package was registering authorization policies that menu items depend on. Ensure the package is fully removed and no references to it remain.
- **"Unable to find a module by assembly" errors** – A removed package registered menu providers that are still referenced. Ensure the package is fully removed and no references to it remain.

## Rollback and recovery

If the upgrade fails, the recovery procedure depends on whether the failure occurs before, during, or after first startup. First startup is the first time the CMS 13 application launches against the database, when the migration runs automatically.

The following sections cover three failure scenarios: before first startup, during or after first startup, and a partial database migration.

:::hint{type="danger"}
**Warning**
The CMS 13 database migration is not reversible. When the migration runs on first startup, it permanently updates the database schema to CMS 13 format. A CMS 12 application cannot run against a CMS 13 database. Your pre-upgrade database backup (which you created in [Prerequisites](docId:1Y3KoWaxY0cxXGcXMbXK8)) is your only rollback path.
:::

### Failure before first startup

If the upgrade fails before first startup (code or package changes only), complete the following steps:

1. Revert your code changes using source control.
2. Run `dotnet restore` to restore CMS 12 package versions.
3. Build the application.
4. Run the application and confirm it works against the original database.

### Failure during or after first startup

If the upgrade fails during or after first startup (database has migrated), complete the following steps:

1. Stop the application.
2. Restore the database from the backup created in [Prerequisites](docId:1Y3KoWaxY0cxXGcXMbXK8).
3. Revert your code changes using source control.
4. Run `dotnet restore`.
5. Run `dotnet build` to confirm the CMS 12 application compiles.
6. Start the application.
7. Verify it runs correctly against the restored database.
8. Check application logs and the migration error output to diagnose the failure before attempting the upgrade again.

### Partial database migration

:::hint{type="danger"}
**Warning**
Do not attempt to re-run the migration against a partially migrated database.
:::

If the migration fails midway, it may leave the database in an intermediate state. Common causes include SQL `Error 1913` and timeouts.

Restore from backup, resolve the root cause, and retry the upgrade from a clean state. For guidance on root causes, see [Database and data considerations](docId:1Y3KoWaxY0cxXGcXMbXK8).

## Deploy on DXP

If your Optimizely CMS is hosted on DXP, the deployment path depends on whether you are already using Optimizely Graph on CMS 12.

### Already using Graph on CMS 12

Because there are schema-breaking changes to Optimizely Graph between CMS 12 and CMS 13, you need a dedicated migration process to create a new CMS 13 project alongside your existing CMS 12 project. This lets you validate the upgrade without impacting your live site.

See [Migrate from CMS 12 to CMS 13 with Optimizely Graph](docId:5IIpWhRi9sd4hvXlqyaHY) for detailed steps.

### Not yet using Graph on CMS 12

If you have not yet implemented Graph on CMS 12, your migration path follows the standard upgrade process in the PaaS Portal. Graph provisioning is added as an extra step in your existing CMS project. Deploy to Integration, then Preproduction, and then Production. In this case, there is no CMS 12 production instance running in parallel with a CMS 13 production instance.
