---
title: Migrate DAM from CMS 12 to CMS 13
slug: cms-13/docs/migrate-dam-from-cms-12-to-cms-13
docTags: 
createdAt: 2026-10-08T21:30:00.000Z
---

After you upgrade from CMS 12 to CMS 13, Optimizely Digital Asset Management (DAM) assets display as broken or empty. This affects images, videos, and documents in edit mode and on your site. Migrate the DAM asset references to display these assets again.

Existing content still references the CMS 12 DAM content provider, but CMS 13 serves DAM assets through Optimizely Graph. The **Optimizely DAM Legacy Asset Migration** scheduled job updates these references to the CMS 13 format. After the job updates references, it deletes legacy CMS 12 tracking data, as described in Cleanup of legacy tracking.

## What the migration updates

The job updates DAM references in the following property types:

- `ContentReference`
- `IList<ContentReference>`
- `ContentArea`, including inline blocks
- `Url`
- `LinkItem` and `LinkItemCollection`
- `XhtmlString`
- Block properties and block lists

The job migrates references to images, videos, documents, and image and video renditions. It processes published content, drafts, earlier versions, all language branches, and content in the trash. The job updates existing versions in place and does not create versions, so version history stays intact.

## Cleanup of legacy tracking

After the job updates references, it deletes the CMS 12 asset tracking records from CMP. It also deletes the legacy asset mapping rows from the CMS database. Cleanup applies only to assets that the job migrated completely.

The job skips or stops cleanup in the following cases. Content changes from the migration remain in every case.

- **No CMP credentials** – The job skips cleanup when `ClientId` and `ClientSecret` are not configured. Configure `ClientId` and `ClientSecret`, and then rerun the job to complete cleanup.
- **Content from an external content provider** – The job does not process this content. When the content tree includes such content, the job skips cleanup so that the legacy records stay available.
- **CMP errors** – The job retries temporary failures and rate-limit errors. To change the retry counts, see the Optional migration settings section. The job stops cleanup when CMP returns an authentication error or repeated rate-limit errors. To complete cleanup, correct the credentials or wait for the rate limit to clear, and then rerun the job.

## Migration limitations

Consider the following limitations when you plan the migration:

- You cannot undo the migration from the CMS UI. To revert it, restore your database backup.
- Run time depends on the amount of content, because the job reads every content version.
- The job includes content in the trash. Editors can restore content from the trash. If the job excluded that content, restored items would have broken references after cleanup.
- The job does not check whether assets still exist in DAM. It derives the CMS 13 references from the CMS 12 mapping data.

## Prerequisites

Confirm the following before you run the migration:

- Your site runs CMS 13.3.0 or later.
- You have access to **Settings** in CMS.
- You have activated DAM features for each asset type that your content uses. Go to **Settings** > **Optimizely DAM Features**, and select **Activate this feature** for **Images**, **Videos**, or **Documents**. You cannot deactivate a DAM feature after you activate it. See [Configure the DAM asset picker for CMS 13](docId\:TL59_p9hyGaBWt3YnCpO1).
- All DAM assets are synced from Content Marketing Platform (CMP) to Optimizely Graph. Optimizely Graph also has content sources for images, videos, and documents. If assets are not synced, editors cannot find or select them after the migration. See [Enable Graph service to sync DAM and CMS](docId\:GHPdKRxNshVI1_ghsWOXf).
- You have configured CMP client credentials (`ClientId` and `ClientSecret`) under `Optimizely:Cmp:Client`. The job needs these credentials for cleanup.
- You have a full backup of the CMS database.

## Install and enable the migration job

Add the package, register the services, enable the job, and deploy the changes in your CMS 13 project.

1. Add the `EPiServer.Cms.DamMigration` NuGet package to your project:

```xml
<PackageReference Include="EPiServer.Cms.DamMigration" Version="13.3.0" />
```

2. Register the migration services in `Program.cs` or `Startup.cs`, after the DAM UI services:

```csharp
services.AddDamUI();
services.AddDamMigration();
```

3. Enable asset tracking and the migration job in `appsettings.json`. Merge these settings with your existing `Optimizely` configuration:

```json
{
  "Optimizely": {
    "Cms": {
      "DamUI": {
        "TrackingEnabled": true
      },
      "DamMigration": {
        "Enabled": true
      }
    }
  }
}
```

The settings in the previous code sample do the following:

- `TrackingEnabled` – Displays the **Optimizely DAM Tracking Assets** job, which reports DAM asset usage to CMP. Run this job before the migration. The default is `false`.
- `Enabled` – Displays the **Optimizely DAM Legacy Asset Migration** job and lets it run. The default is `false`.

4. Rebuild and deploy your project so the package, service registration, and settings take effect.

## Run the migration

Run the tracking job first to confirm that CMS connects to CMP, then run the migration job. For information on the scheduled jobs UI, see [Scheduled jobs through the UI](docId\:BQqAH5s9lZpCAp6f6om60).

:::hint{type="warning"}
**Important**
The migration updates content versions in place and, when cleanup runs, deletes legacy tracking data. You cannot undo the migration from the CMS UI. To revert it, restore your database backup.
:::

1. Go to **Settings** > **Scheduled Jobs**.
2. Select **Optimizely DAM Tracking Assets**.
3. Click **Start**.
4. On the **History** tab, confirm that the job completed without errors. If the job reports errors, do not start the migration job. Resolve the errors, and run the tracking job again.
5. Select **Optimizely DAM Legacy Asset Migration**.
6. Click **Start**.
7. When the job completes, review the result in the **Message** column on the **History** tab.

A completed run reports the number of resolved assets and updated versions. When cleanup runs, the message also reports the cleanup result, as in the following example:

```text
Migration completed: 22 DAM assets resolved, 140 CMS versions patched. Cleanup completed after migration: processed 22 DAM identities, untracked and deleted 22, failed 0.
```

If the job cannot resolve some assets, the message lists how many and why. The log lists each unresolved asset, up to the `MaxReportedFailures` limit. Fix each cause, and then rerun the job. The following causes are common:

- **Inactive asset type** – An asset type is not active on the **Optimizely DAM Features** page. Activate the asset type.
- **Invalid mapping data** – The CMS 12 asset mapping table contains invalid data. This table stores the CMS 12 identity of each DAM asset.

If no asset type is active, the job stops with `No DAM content source is configured; nothing to migrate.`

## Rerun or stop the migration

The job saves its progress as it runs, so reruns and stops are safe.

- **Rerun** – Start the job again. The job skips references that it already migrated.
- **Stop** – Click **Stop** on a running job. The job keeps completed work, and the next run continues from the last saved point.

## Verify the results

Open several pages and blocks in edit mode, and check the following content:

- Images and videos in asset properties
- Links to documents in link and URL properties
- Content areas, including inline blocks
- Rich text
- Drafts and other language branches

Check the same pages on your site.

## Finish the migration

Complete this step after cleanup finishes. If the job skipped cleanup, resolve the cause and rerun the job first.

Update your configuration after you verify the results:

- Set `Optimizely:Cms:DamMigration:Enabled` to `false` to hide the migration job.
- Keep `Optimizely:Cms:DamUI:TrackingEnabled` set to `true`. The **Optimizely DAM Tracking Assets** job then continues to report DAM asset usage to CMP.

## Optional migration settings

Adjust batch sizes, concurrency, and retries under `Optimizely:Cms:DamMigration` when the defaults do not fit your site. The defaults suit most sites. At startup, CMS validates these values. If a value is out of range, CMS does not start.

| Setting                              | Default | Allowed values | Description                                                                              |
| ------------------------------------ | ------- | -------------- | ---------------------------------------------------------------------------------------- |
| `TraversalChunkSize`                 | 100     | 1–10,000       | Content items processed between progress saves.                                          |
| `ChildPageSize`                      | 500     | 1–5,000        | Number of child content items that the job loads at a time.                              |
| `VersionPageSize`                    | 500     | 1–5,000        | Number of content versions that the job loads at a time.                                 |
| `PageSize`                           | 200     | 1–5,000        | Number of legacy assets evaluated per cleanup batch.                                     |
| `MaxConcurrency`                     | 4       | 1–32           | Number of legacy assets evaluated at the same time during cleanup.                       |
| `CleanupTransientRetryCount`         | 2       | 0–10           | Cleanup retries for temporary CMP failures.                                              |
| `CleanupRateLimitRetryCount`         | 1       | 0–10           | Cleanup retries for CMP rate limiting.                                                   |
| `CleanupRetryDelaySeconds`           | 1       | 0–60           | Starting delay, in seconds, before a cleanup retry. The delay increases with each retry. |
| `CleanupCircuitBreakDurationSeconds` | 60      | 1–3,600        | Time, in seconds, that cleanup pauses calls to CMP after repeated failures.              |
| `MaxReportedFailures`                | 100     | 0–1,000        | Maximum number of unresolved assets listed in the log. Totals by reason are exact.       |
