Module: Migrate widgets and custom code
2 of 9 Pages
Migrate widget data as reusable content
In this technical deep dive, we will show you how to migrate widget data from Kentico Xperience 13 (KX13) into reusable content items when upgrading to Xperience by Kentico (XbyK). You will learn how to use the Xperience by Kentico: Kentico migration tool together with custom widget migrations to transform widget data into reusable content items in Content hub, and reference those items from your migrated widgets in XbyK.
This material focuses on practical widget data migration and code adjustments, exploring the approach that combines Source item API discovery with targeted adjustments we talked about in our Upgrade widgets from Kentico Xperience 13.
Understand our migration scenario
For this example, we’ll be using the Hero image widget from the KX13 Dancing Goat sample site.

Currently, the Hero image widget in KX13 stores all its data directly within its property configuration, which lives in the CMS_Document table for each page. It has these properties:
- An image for the background
- A text for the heading
- A button text for the call-to-action
- A button target URL
- A theme selector for light or dark styling
Each widget instance requires editors to manually fill out all this information, and the content can’t be reused across different pages.
Together we’ll extract the content-related properties (Text, ButtonText, ButtonTarget) into reusable content items stored in the Content hub, while keeping the presentation properties (Image, Theme) in the widget itself. As a bonus, we’ll enhance the widget by adding a custom button text override option and a new “Open in new tab” property.

Map out the widget upgrade workflow
The Kentico migration tool allows you to migrate data iteratively, which we will take advantage of in this scenario. Here’s our roadmap:
- Run the initial data migration excluding the pages that contain Hero image widgets.
- Create the target content type in your XbyK instance and generate its code files.
- Build the custom migration logic to transform your widget content.
- Run the migration with our custom logic to transform the widget data.
- Adjust the widget code in the target XbyK instance.
Keep these migration best practices in mind:
- When checking your migrated widget data in the database, always look for GUIDs, not IDs. Numerical IDs will not necessarily match between KX13 and XbyK. They are generated fresh for each new object in a database.
- Create database backups between successful migrations so you can roll back if needed.
- To troubleshoot, you can enable detailed (trace) logging in the migration tool:
...
{
"Logging": {
"LogLevel": {
"Default": "Information",
"System": "Warning",
"Microsoft": "Warning",
"Migration.Tool.Source.Services.VisualBuilderPatcher": "Trace",
"Migration.Tool.Extensions.CustomWidgetMigrations": "Trace"
},
...
Migrate your site data without widget pages
Let’s start by migrating your site data while excluding the pages that contain our Hero image widgets. You can approach this in two ways: either exclude pages entirely using migration command parameters, or exclude specific objects in the migration tool’s configuration file.
For our example, we’ll use the command parameter approach to migrate everything except pages:
.\Migration.Tool.CLI.exe migrate --sites --custom-modules --users --settings-keys
This gives us a clean foundation to work with. Later, we’ll run the migration again with our custom widget migration logic to handle all Hero image widgets across the Dancing Goat site.
Before running any migration command, make sure you have:
- Your source KX13 instance running
- Your target XbyK instance stopped
- Source instance API discovery enabled in your migration configuration
- You’ll need this for the widget migration we’ll build later; see an example in upgrade walkthrough.
After a successful migration, you should be able to run your target instance. When you sign in to the administration, you’ll see that the DancingGoatCore site has become a website channel without any pages.
Set up the Hero reusable content type
Now we need to create the Hero reusable content type that will store our migrated widget content in the Content hub.
Define the content type in administration
Start your target XbyK instance and navigate to the Content types application in the administration interface. Create your Hero content type with these settings:
- Content type name: Hero
- Namespace: DancingGoatCore
- Name: Hero
- Icon: Choose any icon you like
- Use for: Reusable content (this is crucial—it makes the content available in the Content hub)
- Short code name: Leave the auto-generated value

Add these three fields, each of the Text type, marked as Required and using the Text input form control:
- HeroHeading
- HeroTarget
- HeroCallToAction

Generate code files
Now let’s generate the strongly-typed C# classes for our new Hero content type. Make sure you have the DancingGoat.Entities project set up first—see our upgrade walkthrough for details.
Run this command from your main project’s root directory (in our case, the DancingGoat.Web folder):
dotnet run --no-build -- --kxp-codegen --type "ReusableContentTypes" --namespace "DancingGoatCore" --location "../DancingGoat.Entities/{type}/{name}"
You’ll find the generated Hero.generated.cs file in your DancingGoat.Entities project under the ReusableContentTypes folder. It should look like this:
//--------------------------------------------------------------------------------------------------
// <auto-generated>
//
// This code was generated by code generator tool.
//
// To customize the code use your own partial class. For more info about how to use and customize
// the generated code see the documentation at https://docs.xperience.io/.
//
// </auto-generated>
//--------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using CMS.ContentEngine;
namespace DancingGoatCore
{
/// <summary>
/// Represents a content item of type <see cref="Hero"/>.
/// </summary>
[RegisterContentTypeMapping(CONTENT_TYPE_NAME)]
public partial class Hero : IContentItemFieldsSource
{
/// <summary>
/// Code name of the content type.
/// </summary>
public const string CONTENT_TYPE_NAME = "DancingGoatCore.Hero";
/// <summary>
/// Represents system properties for a content item.
/// </summary>
[SystemField]
public ContentItemFields SystemFields { get; set; }
/// <summary>
/// HeroHeading.
/// </summary>
public string HeroHeading { get; set; }
/// <summary>
/// HeroTarget.
/// </summary>
public string HeroTarget { get; set; }
/// <summary>
/// HeroCallToAction.
/// </summary>
public string HeroCallToAction { get; set; }
}
}