A Guide to Migrating from Sitecore TDS to SCS

A client I’m currently working with recently upgrade to Sitecore 10.3 and I was tasked with migrating our TDS projects to the much newer Sitecore Content Serialization (SCS). I imagine a lot of people need to do this so thought I’d share the approach I took and steps I followed to do this. 

Why migrate to SCS?

SCS is now the de facto standard for Content Serialization for Sitecore – not only for Sitecore XP but also for XM Cloud too. It has now matured to a point where it has all the features we should need as Sitecore developers and is well established. It’s also built in an modern way so is easy to use and very fast.  

If you are currently using TDS then this is now end of life/legacy and will likely soon not be supported. In addition to this; managing items via TDS is tedious and slow. With SCS we can just run the watch command and pickup changes from Sitecore without having to manually add items, which will be a lot quicker. You also need a license for TDS and don’t for SCS (via the CLI at least). 

I‘ve always preferred Unicorn to TDS, but on the current project I’m working on TDS was already implemented. If you are using unicorn though there are similar approaches to migrating from Unicorn to SCS too.

Differences between TDS project files and SCS Modules

TDS Project files are a proprietary XML based and contains list of all the items to Serialize, they are designed to be used via the TDS Visual Studio plugin to manage items.

SCS Module files on the other hand are JSON based files which include a list of the files to sync. The items are then serialized to Disk as .YAML files. The format is a little different for these but essentially the definition is quite similar. Here is a nice comparison from Jason St-Cyr’s blog post:

Approaches to Migration

There are two different approaches to migration to consider here.

Manual Migration

You could manually migrate each TDS project item by item but unless your working on a very small Sitecore project or you’ve not got many items in source control this will likely take quite some time so I wouldn’t recommend it.

Tools to Automate Migration

I spent quite a while looking around the Sitecore community to see what was already out there and there were 3 pretty good options that I found:

  1. Sitecore Serialisation Converter by Joseph Long – .Net console app. supports item and role serialization, full featured: save path/relative save path, ignore list etc.
  2. A PowerShell Script by Aaron Bikle – impressive power shell script, less feature rich than Sitecore Content Serializer but does support an ignore list and consolidate paths which is nice.
  3. TDSC by Matthew Ellins – a .Net Core console app. Supports item serialization but not roles. Not as full featured as Sitecore Serialisation Converter.

I looked at all of these and tested them but ultimately landed on Sitecore Serialisation Converter as it was the most full-featured, robust and flexible option.

I did however make quite a few updates to it and raised an PR – which has been merged today by Joseph so you can take advantage of them too:

  • Improved the error handing by adding more checks around various aspects and logging out all errors/warnings and progress
  • Added logging via log4net (ssc-skipped.log and ssc-all.log)
  • Added tracking of errors/stats with summary at end of success, failed, skipped etc
  • Automation of the Json module listing to add to your Sitecore.json file
  • Added support for removing ‘TDS’ from module/namespaces (StripTDSFromName option) – for if you have TDS included in the name of your TDS projects and want to remove it.
  • Added support for Filtering on just  specific project name (ProjectNameToMatch option) – to allow running on a single project/testing. Leave blank to include all Projects.
  • Added a new SkipCreateIfExists option to not create the Json file if it already exists.
  • I also stole some of Aaron’s exclude list and added that :-).

More info below about how to use this.

Steps to migrate to SCS from TDS

The following steps give you an overview of the process I followed to migrate to SCS. It’s probably not the only way to do this but it worked well for me and is likely pretty close to the approach you will need to take to do this:

  1. Use Sitecore Serialization Converter to create new SCS Json module files from your existing TDS projects
  2. Update the Sitecore.Json file to include the new modules
  3. Install the Sitecore CLI and run the dotnet sitecore init command to create the Sitecore.json file.
  4. Install the SCS Plugin using the following command:
    dotnet sitecore plugin add -n Sitecore.DevEx.Extensibility.Publishing
  5. Login the CLI to Sitecore
  6. Validate the module files with the command dotnet sitecore ser validate -v and modify them as required
  7. Run dotnet sitecore ser pull -v to sync your items to disk
  8. Resolve any issues with running the pull commands
  9. Push the new modules and .YAML files to source control
  10. Remove TDS projects and TDS item files from the solution
  11. Test the sync to another environment using the -whatif param
  12. Update your release pipeline to remove the TDS sync and add the SCS sync (a blog post will be coming soon on this)

Note: if your struggling with setting the CLI then this is a really useful guide.

I’ve included some tips below on using the SCS commands.

Using Sitecore Serialization Converter

  1. Pull the project from GitHub
  2. Open the project in Visual Studio
  3. Edit the appsettings.config file as follows:
    ProjectDescription – set this to your project name, it will be added to your Module files.
    SolutionFolder – set this to the root of your Solution folder. TDS projects will be found from here.
    SavePath – you probably only want to set this for testing so all module files are created in the same place (use relative path instead to create them in each feature/foundation/project folder).
    UseRelativeSavePath – set to false when testing using the SavePath above, but true when your ready to create the module files in a relative location.
    RelativeSavePath – set this if UseRelativeSavePath is set to true above. For me this path was ../.
    StripTDSFromName – set to true if you have the text ‘TDS’ in your project names and it will be removed when creating the .Json files.
    ProjectNameToMatch – set this to filter on one or more projects. Useful for testing or for just targeting specific projects. Leave blank to find all TDS projects.
    SkipCreateIfExists – set to true if you want .Json files to be skipped instead recreated if they already exist. Useful if you’ve run SSC a few times.
  4. Either Run the project in debug mode in Visual Studio OR Build it and go to the .exe in the output folder via command line and run the .Exe like so:
    SitecoreSerialisationConverter.exe
  5. Check the console/logs for any issues or errors, you should find these in the debug folder
  6. Check the summary looks correct in the Console and the Logs and no projects or important items are missing
  7. Copy your Module list from the output in the Console to use in your Sitecore.json file, e.g:

    "modules": [ c:/temp/MyProject.Project.Master.module.json",
    c:/temp/MyProject.Feature.Banner.Master.module.json",
    c:/temp/MyProject.Foundation.Caching.Master.module.json
     ],


Tips on Serialize Commands

  • Verbose – Run all the commands with -v after them so that you get full debugging of any issues. e.g: dotnet sitecore ser validate -v -i MyProject.Feature*

  • Filters – Use the -i param to filter by a specific project name pattern, e.g: dotnet sitecore ser pull -v -i MyProject.Feature* – will match all projects starting with ‘MyProject.Feature’

  • Validate – Use the validate command to check the your Module Json file paths are valid. e.g: dotnet sitecore ser validate -v. You can combine this with -i to validate just one project at a time.

SCS Issues and Errors

I hit a bunch of errors when trying to run the pull and/or validate command. I think I had perhaps 100 errors or more to resolve across around 60 converted TDS projects so it took me quite some time to resolve them all. It’s definitely easier if you target on Project at a a time, fix the issues, commit to source control and move to the next though. Here are the issues I tracked and what I had to do to fix them.

Duplicate Paths cannot be serialized

If this happens it means you have multiple module files which have references to the same item/path. You need to find the duplicate references and remove the path from all but one Module file and try and run the command again.

Non Unique Paths cannot be serialized

If this happens it means an item with the same name exists more than once in Sitecore and it’s trying to serialize it to disc as an YAML file but can’t create the item more than once with the same path name.

To fix it remove one or more copies of the item from Sitecore and try and run the command again. You will need to work out which is the correct one to remove. I used SPE to remove items by ID to speed this up.

Serialized item contained a blank value

You will see an error like so if this happens:

Check your serialised item, you will see there is no language set. Then check the language versions in Sitecore and look for an Invariant Language. I found I had to run an SQL command on my master and core database to remove version languages:

DELETE FROM [sitecore_master].[dbo].[VersionedFields] WHERE [Language] = ''

DELETE FROM [sitecore_core].[dbo].[VersionedFields] WHERE [Language] = ''


Blank Database Values

There were some situations where the database in my Json files ended up empty for some reason. I did make some updates to the Sitecore Serialization Converter to fix this by defaulting the value to Master if the Project name contains ‘Master’ and Core if it contains ‘Core’. But if this happens to you then you will need to fix this manually in the Json files else SCS will throw errors:

Cache already contains GUID

I also had some errors related to items already existing in the cache, something like:

/sitecore/content/* (GUID) attempted to be cached, but the cache already contained /sitecore/content/*. Non-unique paths cannot be serialized. Please choose a different item name.

If you get this error then you should be able to fix it with the following command or perhaps a combination of this fix and the non unique items fix:

dotnet sitecore ser validate --fix

Source Control

One other thing to consider is how you approach adding your changes to Source Control to allow for easy tracking of changes and roll-back etc. I did this my adding all my Json module files first and then pulling each Helix layer (feature/foundation/project) one at a time and pushing the Yaml files in batches.

Next Steps

The next steps for me are adding the integration with the CLI to Github Actions, pushing the items from Source control to other environments and removing the TDS projects and serialized files. I will write about this in a future blog post.

Links

As usual there were a lot of links that helped with this, here are some of them:

https://sitecore.stackexchange.com/questions/36312/how-to-migrate-from-tds-to-cli

https://amitkumarmca04.blogspot.com/2021/07/Sitecore-Content-Migration-Using-Sitecore-Content-Serialization.html

https://spyn.me/sitecore-migrating-from-tds-to-scs/

https://sitecore.stackexchange.com/questions/33034/guid-attempted-to-be-cached-but-the-cache-already-contained-sitecore-c

https://jasonstcyr.com/2023/11/28/converting-a-tds-project-to-sitecore-content-serialization-scs/#:~:text=Migrating%20from%20TDS%20to%20Sitecore,start%20working%20with%20XM%20Cloud!


Hopefully this is useful to others who need to do this.

My thoughts on SUGCON 2016 – Day 2

badgeThere was an early start for Day 2 (especially after a late-ish night involving a few strong Danish Beers), but I knew there were some intriguing talks today so didn’t want to miss anything.

You can read about Day 1 here if you missed it.

The first session that caught my interest was Nick Wesselmans talk on how Active Commerce use SIM, Powershell, Octopus Deploy and Azure to automate product builds.

Using SIM, Powershell, Octopus Deploy and Azure to automate product builds.

Nick gave an overview of how they created a PowerShell wrapper for SIM to automate Sitecore instances for product builds for their Active Commerce product.

IMG_5762

He also talked about how they use Sitecore Power Shell Extensions (SPE) to do things like automate publishing, rebuild the links database and initialise Sitecore Zip package builds. I’ve experimented with SPE but I’ve not used it in anger and this has given me ideas for how I might use it more on current or future projects.

IMG_5764

Finally, he talked about their use of Octopus for deployment of packages and invoking PowerShell scripts and Azure IaaS and Azure Blob Storage and AzCopy which is used for quickly spinning up VMs for hosting the product build and test environments. I liked the idea of these being scripted to only run during business hours.

IMG_5768

The Active Commerce team also use Bamboo for their build server (but are thinking of moving to Team City). Nick showed us that their build pipeline looks like this:

IMG_5773

It was nice to see some familiar approaches here, albeit with different tools in some instances and some new ideas too.

You Me and Sitecore MVC

After a short break Kern Herskind delivered and entertaining (and Circus themed) presentation on Sitecore MVC. He even rode a unicycle at the end!

IMG_5777

Kern gave a general overview on MVC for those not familiar with the concepts and then how Sitecore MVC works and whats available out of the box. Not much of this was new to me but it was good get a refresher anyway.

Then Kern talked through some of the downfalls of Sitecore MVC and how he has gone about solving them. Things like renderings not being able to alter any HTML that is rendered prior to them being rendered and multiple form posting issues.

IMG_5781

IMG_5782

IMG_5783

We then go a sneaky peak of what coming up for Sitecore MVC, such as abstract base classes and better ServiceLocator and DI support:

IMG_5869-3

IMG_5873

Kern finished by talking about the future of Sitecore MVC and expectations for the future.

IMG_5787

Good to see better documentation and closing feature gaps on the list of improvements.

IMG_5788

The key message here being that Sitecore MVC is going to continue to be the preferred UI Framework.

Hedgehog then did a quick talk on their TDS product and helped to answer the question a lot of developers might have, “why should I pay for TDS instead of using Unicorn”.  The answer is probably in these two slides, maybe go and show them to your Boss :-).

IMG_5791

Essentially it does a lot more besides just syncing items between sitecore instances:

IMG_5792

I haven’t used it but I’ve head good things about it from other Sitecore Developers.

After lunch (which was excellent by the way) I opted to attend two talks on Sitecore Habitat. One by Ruud Van Falier called Introducing Sitecore Habitat and the 2nd by Anders Laub on Practical Habitat: Embrace the Architecture.

Introducing Sitecore Habitat

For those who don’t know what Habit is, it is an Architecture approach for Sitecore development and is designed to give best practice guidance on how to structure your Sitecore projects. I have taken a look at it a few times but not really used it and the feedback from other Sitecore developers I’d spoken to was that it was quite complicated, so I was interested in finding out more about it.

Ruud was presenting to a packed room with quite a few developers stood up at the back, obviously as keen as me to know more. He started with the basic concepts of Habitat, explaining how all modules are self-contained and that there should be no communication that goes upwards between modules.

IMG_5796

He also explained the the 3 layers of Habitat: Foundation, Features, Projects.

layers

Ruud then discussed examples of elements that might live in these layers and how the dependencies flows downwards.

IMG_5806

He then showed the technology stack, which are probably familiar tools to most of you. Sitecore 8.2,  MVC,  Dynamic Placeholders, Unicorn, Bootstrap, JQuery, Sass and Gulp.

A run-through of the Habitat solution structure then followed and an explanation of the different build tasks used.

build

There was then a more in-depth explanation regarding Modules:

IMG_5816

IMG_5818

IMG_5820

And then more detail on layers:

IMG_5822

IMG_5828

IMG_5832

IMG_5834

Finally, a pros and cons slide and questions:
IMG_5836

Ruud was honest about the fact that Habitat is in the early stages and is changing every day, he also said it’s not meant to be taken as a ‘Boiler Plate’ for Sitecore solutions – more a guideline. However, I left the session will a lot of things to investigate further and will definitely be taking a closer look at Habitat and how some of It’s concepts can be applied to the projects I am working on.

Practical Habitat: Embrace the Architecture

With my appetite now whetted for Habitat I went straight to the next session on embracing the architecture.

Anders talk started with a general discussion around Architecture and then moved to Habitat and why Pentia use it as an architecture for their solution:

IMG_5837

He then dived into a demo of their solution and explained how it differs to the default Habitat setup. I have a video of this somewhere which I’ll try and add here when I get a minute.

He then discussed a few foundation modules they have created and how it really works well for them as an approach.

IMG_5840

Anders took some tough questions from the crowd well (such as the number of projects in Habitat – which is many) and I think by the end of the session most of the room will be taking another look at Habitat.

Ladies and gentlemen start your testing.

Testing in Sitecore can be notoriously difficult and for some Sitecore developers this means that unit and integration tests that involve the Sitecore context or items are sometimes skipped.  I was interested to see if Alastair had some other ways to implement testing and I wasn’t disappointed :-).

IMG_5844

Alastair Deneys ran us through 4 ways in which to Unit test with Sitecore. The first was an interesting one and was to essentially install Sitecore in your application and then run the tests from an asp.net web page test runner.

The 2nd and 3rd were to add a minimal or full Sitecore config files and the Sitecore dlls you need to your nunit test project and run It. This worked pretty well but as Alastair said, isn’t proper unit testing as it’s using real data.

The 4th was to use FakeDb to mock the Sitecore items you need to run your tests. I’d heard about FakeDb before but not used it so it was nice to see an example of how this is done.

IMG_5855

Alastair also showed us how Sitecore.LiveTesting can be used to spin up an instance of Sitecore in a container in the background to test against.

IMG_5856

IMG_5863

It was a bit slow but seemed really cool and definitely something I’m going to experiment with.

IMG_5868

The key message here was, whatever you do make sure you create tests and don’t get hung up on if they are real unit tests or actually integration tests.

Sadly it was now time to head to get our flight home so I missed out on the last talk of the day by Martina Welander on refactoring doc.sitecore.net, hopefully I can find it on Google Hangout.

SUGCON was a great experience and It has given me a whole lot of ideas and things to look into for current and future Sitecore projects. Thanks to the Sitecore Community and the sponsors for putting on the event.

My only regret is not having chance to chat to any of the MVPs who have been so helpful on Slack and on their blogs, but I’ll definitely be back next year so I’ll buy you a beer or two then instead.

Till next time.

IMG_5878