Sitecore To Umbraco (2)
Umbraco

Sitecore to Umbraco Migration

Sitecore to Umbraco Migration

A Story from the Engineering Point of view

Our team's field notes from the real engineering work behind a Sitecore to Umbraco migration like foundations, media, content tree, components, code, search, and the sync script that kept us sane.

The call that started it all

Some time back, our team got a call that we have heard many times before. On the other end was a client whose website had been running on Sitecore for the better part of a decade. The platform had served them well. But the renewal was approaching, the licensing costs had climbed, and the editor team had grown tired of the heavy backoffice. The business had made the decision: it was time to move to Umbraco.

On paper, this was a familiar brief. A content-rich, multilingual website serving different audiences by country and service line, built on a mature Sitecore install with its own ecosystem of templates, components, and custom integrations. Our architects nodded, our developers rolled up their sleeves, and the proposal went out. And then, as these things always go, the real work began.

What follows are the field notes from that migration, the technical puzzles we solved, the moments where we had to think again, and the small victories that only an engineering team quietly celebrates with the second cup of coffee for the day. We have changed enough details to keep the client's name out of it, but anyone who has lived through a long Sitecore migration will recognise every chapter.

The foundation: Templates, properties, and the component inventory

Before a single line of migration code was written, we spent a focused ten days doing one thing: understanding what actually lived inside the Sitecore installation.

Our analysis went deeper than a surface tour. We catalogued every Sitecore template, line by line, with every field, every data type, and every validation rule. We did the same for the renderings and datasource templates the reusable components that gave the pages their shape. Settings items, which the business had used over the years to centralise everything from site configuration to feature toggles, got their own inventory. Standard scaffolding, bucket folders, reference items, media types all of it got tracked.

What we ended up with was a single master spreadsheet, several hundred rows long, that became the quiet hero of the whole project. For every Sitecore template, we captured:

  • The template name, the path, and whether it was still being used anywhere.

  • Every field on it, with its Sitecore field type like Rich Text, Droplink, Multilist, Image, Date, General Link, and so on.

  • The Umbraco Data Type that would replace it i.e. Richtext Editor, Content Picker, Multinode Treepicker, Media Picker, Date Picker, Block List, and so on.

  • The Umbraco Document Type or Element Type it would belong to.

  • Any custom validators, source queries, workflow rules, or restriction logic that needed to be preserved.

Alongside the template analysis, we did the same for components. Every rendering, every datasource template, every parameter template got its own row. We recorded the component name, the fields it exposed to editors, the configurations around it (country restrictions, service restrictions, audience segmentation flags), and the Umbraco Element Type that would host it inside a Block List or Block Grid.

The settings models, those quiet Sitecore items that drove feature toggles, site-wide configurations, redirect maps, and footer links were catalogued separately and mapped to a dedicated set of Umbraco settings Document Types, so the content tree stayed clean and the configurations stayed easy to find.

This was not glamorous work. It was long whiteboard sessions, careful reading of config files, and a lot of patient “wait, what does this field actually do?” questions. But by the end of it, nothing in the Sitecore installation was a mystery. Every content type, every property, every component, every setting had a clear line of inheritance to its new Umbraco home.

That single foundation list drove every downstream decision, the Document Type model, the migration pipeline shape, the QA matrix, the editor training material. We often say it in our team: a migration without a proper foundation inventory is just a hopeful guess with a timeline attached.

Media Migration: Multilingual alt text and country-based restrictions

Media was never going to be a straightforward copy-paste for this project.

The site served different content to different countries and different service lines, and that logic reached all the way down into the media library. An image used on a country-specific banking page could not appear on a global page. A PDF for a specific service was gated behind the service landing. Alt text existed in multiple languages and often said different things in each not word-for-word translations, but genuinely different descriptions tuned for the audience.

Our media migration pass had to carry all of this across, not just the files.

We extended the standard media export to pull every item along with its full metadata the country tags, the service tags, the publication status, and critically, the alt text in every active language. On the Umbraco side, we built a dedicated Media Document Type with explicit properties for country, service, and multilingual alt text, so the restrictions became a first-class part of the media model rather than something buried inside a workflow nobody wanted to touch.

A few things we were particular about:

  • Alt text was migrated per language, with gaps flagged in a report so the content team could fill them in not quietly carried over as the primary language in both.

  • Country and service tags were preserved exactly as the Sitecore model had them, so the downstream filtering logic in the templates kept working from the first day.

  • Protected media stayed protected. We mapped the Sitecore access rules into Umbraco's public access and member group rules, with a test pass to confirm that a country-restricted PDF really did refuse to open for an unauthenticated out-of-region visitor.

  • The folder structure was rebuilt around how editors actually thought about assets by service and brand, with country sub-folders where it made sense not around the historical folder drift.

  • Every file carried its original Sitecore item ID as a property on the Umbraco media node, so the rich text and content link rewriting (coming up next) could resolve every legacy media reference without guessing.

By the end of the pass, every media file lived in the right place, carried the right metadata, and respected the right restrictions. The content team's first reaction when they saw the new Media section was, in their own words, “this is finally logical.”

Automating the content tree migration

With the foundation list in hand and the media moved across, the next big piece was the content tree itself the actual pages, with their parent-child relationships, publishing states, and language variants.

Doing this by hand was never going to work. The site had thousands of items, and the structure needed to be reproduced in Umbraco exactly. One wrong parent, one dropped item, one missed language variant, and the client's editors would spend months finding and fixing the gaps. So we built an automation.

The flow was straightforward in principle. On the Sitecore side, we exported items in bulk using a serialisation pass that preserved the full tree, the item IDs, the created and modified timestamps, the workflow state, and every language variant. On the Umbraco side, we wrote a .NET tool that read the export, walked the tree depth-first, and used the Umbraco ContentService to create each item under its correct parent with the right Document Type from our foundation list, the right properties, the right publishing state, and all its language variants in one go.

The nice thing about this flow is that the output is deterministic. For the same export, the Umbraco content tree ends up in exactly the same shape every time. No manual reorganisation, no “oh I think this page is supposed to be over here” moments.

A few decisions that paid off:

  • We preserved the Sitecore item IDs as a property on each Umbraco node. This made the rich text link rewriting trivial, because every legacy internal link could be resolved to its new Umbraco node without any guessing.

  • We honoured the publishing state. Pages published in Sitecore were published in Umbraco. Pages in draft stayed in draft. Pages in workflow landed in the equivalent Umbraco state. The editors did not log in on day one to find hundreds of unexpected drafts to re-publish.

  • Dates were preserved. Created and modified timestamps on the Umbraco side matched Sitecore, so the editors' mental maps and recent-items lists still made sense.

  • Language variants were created in a single pass per node, not as separate items, so the Umbraco multilingual model stayed clean from the first run.

By the time the content tree script was running cleanly end to end, we were doing a full tree migration in roughly forty minutes. Which, considering the manual alternative would have taken weeks and still produced errors, was a very good trade.

Components and Rich text: Every configuration preserved

Pages are not just text in a container. On any mature site, pages are made of components i.e. hero banners, feature grids, quote blocks, call-to-action cards, each with its own set of properties and, in this project's case, each with its own conditional display rules.

The Sitecore datasources carried a lot of that logic. A single hero component on a product page could be configured to show different content for different countries, different services, and even different user segments. The rich text fields within those components often had restriction classes and data attributes that the frontend used to show, hide, or re-order content at render time.

Migrating this layer meant carrying across not just the content but the entire set of configurations around it.

Our approach was built around the Block List and Block Grid editors in Umbraco. For each Sitecore datasource template in our foundation list, we created an Umbraco Element Type with properties that mirrored the Sitecore fields one to one including the country and service restriction properties, the segmentation flags, and any visibility rules that had been encoded in the data model.

For the rich text migration itself, we built a transformation layer that was gentle on the content but strict on the metadata:

  • Every rich text block was parsed with a proper HTML parser, cleaned of the usual Sitecore and Word artefacts, but every data attribute and class name that carried business meaning was preserved exactly.

  • Internal links were rewritten from Sitecore item IDs to Umbraco content links using the ID lookup we had built during the content tree migration.

  • Media references were rewritten to Umbraco media picker references using the media ID lookup from the media pass.

  • Restriction metadata, the country, service, and segmentation flags embedded in the markup was carried across untouched, so the frontend rendering rules did not need to change at all.

  • Anything the pipeline could not confidently transform was flagged in a human-readable report, so an editor could make the call rather than the script quietly guessing.

The result was that an editor opening a migrated page in Umbraco saw the same components, in the same arrangement, with the same restriction rules as the Sitecore original. The only visible difference was the backoffice itself, which was now considerably easier to use.

Code and functionality

A website is not just its content model and its pages. Behind the scenes, every mature site has a quiet layer of custom code doing real work i.e. custom publishing rules, event handlers that fire when content changes, scheduled jobs that reindex or revalidate, little pipelines that enforce business rules nobody remembers writing down but that are keeping the site honest.

Our rule on this layer was simple: not a single business requirement gets quietly dropped during migration.

Alongside the content audit, we did a full code audit of the Sitecore solution. Every pipeline processor, every event handler, every scheduled task, every custom command, every helper utility, all of it got catalogued, with a short description of what it did and why it existed. For anything that was unclear, we tracked down the person who could explain it. If nobody could, we treated the behaviour as business-critical by default until proven otherwise.

Each item on the code list then got mapped to its Umbraco equivalent:

  • Sitecore pipelines and event handlers mapped neatly to Umbraco Notification Handlers, which hook into the same content lifecycle events saving, publishing, deleting, moving.

  • Sitecore commands that ran in response to backoffice actions became Umbraco composers that registered equivalent services and endpoints.

  • Scheduled Sitecore agents became Umbraco scheduled tasks running under the hosted-service model.

  • Custom validators, workflow rules, and publishing restrictions were rewritten against the Umbraco notification model.

  • Caching layers, custom index rebuilders, and admin dashboards were reviewed one by one and either migrated as-is or rebuilt from scratch where the new platform offered a better path.

The QA phase for this layer was built directly from the code audit list. Every mapped item had a test case. Every test case had to pass before we called the functionality migration done. If a test case needed a particular content set to exist, we included that set in our migration fixtures so the test could run against real-looking data.

The result was a go-live where no editor was surprised by a missing automation, no business user discovered their favourite report had quietly stopped running, and no silent cron job turned out to have been doing something important nobody had told us about. Every business requirement that had existed on the Sitecore side existed, verified and tested, on the Umbraco side.

Simplifying search: The happiest moment we cracked

If there is one moment on this project the team still talks about, it is the search one.

The Sitecore site had grown an elaborate search layer over the years. An external search service, custom indexing jobs, a translation layer between the search service and the rendering code, a cache in front of that, and a sprinkling of custom code that nobody fully understood holding it all together. Response times were slow. The relevance was good but not great. Adding a new searchable property meant touching four or five different places, and every change carried the small risk of breaking something that had been running since 2019.

When we first mapped the architecture out on the whiteboard, we stared at it for a good minute in silence.

Then one of our senior engineers asked the question that quietly changed the whole project: “do we actually need any of this on the Umbraco side? Why are we not just using Examine?”

Umbraco Examine, for anyone who has not worked with it, is a search layer built right into Umbraco. Lucene under the hood, local to the application, no external service to maintain, no indexing lag, and a clean API that developers can extend without a six-hour onboarding call. For most sites, it is more than enough.

We did a quick proof of concept. We rebuilt the core search queries against a sample Examine index, benchmarked them, and compared the results to the legacy system. The findings were honestly a little humbling. Examine was returning the same quality of results in a tiny fraction of the response time, with roughly a tenth of the code around it. The whole external search service, the cache layer, the translation code, the custom indexing jobs, all of it could go.

We presented this back to the client with a straight face. We could migrate the existing search architecture as-is, which would take weeks and leave them with the same complexity on the Umbraco side. Or we could replace it entirely with Examine, which would be faster to build, faster to serve, and simpler to maintain for the next five years. Their answer took about four seconds.

The moment we saw the first real search query come back from Examine in under 100 milliseconds, with the right results and no external hop, the whole team let out a quiet cheer. That was, honestly, the happiest moment of the project.

The lesson sits with us: sometimes the right answer to a complicated technical problem is not to migrate it faithfully. It is to look at what the platform you are moving to already does well, and let that replace the complexity you have been carrying for years.

The anytime runnable sync script

The single piece of infrastructure that gave us the most peace of mind through the whole project was the sync script. The sync script was one of the most reliable parts of our migration project. With a single command, we could keep Umbraco in sync with the latest Sitecore content at any stage.

We designed it to be safe to rerun, without creating duplicates or inconsistent data. It handled content, media, components, and rich text transformations.

The biggest advantage was delta mode. Instead of running the full migration, which took nearly an hour, it processed only the changed items and finished in just 3–4 minutes.

This helped us in several ways:

  • Developers could run migrations daily, giving editors a fresh preview every morning.

  • Bug fixes were reflected consistently in the next run.

  • Go-live migration took only a few minutes.

  • Even during hypercare, last-minute content updates were handled smoothly.

We kept the solution simple, reliable, and repeatable. In migration projects, that kind of consistency makes a big difference.

What we take forward

Here are a few lessons we learned from this migration that can help with future projects:

Start with a proper audit: Spend the first two weeks understanding every template, component, property, and setting before starting the migration.

Treat media as content: Preserve permissions, restrictions, and multilingual alt text. These details are important for the editorial team.

Automate content migration early: Build automation from day one and retain Sitecore item IDs in Umbraco. This makes links, redirects, testing, and future fixes much easier.

Preserve component settings: Do not migrate content alone. Carry over visibility rules, restrictions, and segmentation settings that support business logic.

Review custom code carefully: Check every pipeline, event handler, and scheduled job to ensure nothing important is missed.

Use the new platform's strengths: You do not need to recreate everything from the old system. If Umbraco already offers a better solution, make use of it.

Build the sync script early: A reliable script that can run repeatedly and handle only changed content saves time and reduces risks throughout the migration.

Planning a Sitecore to Umbraco migration? Or already working through one? Our team has been through this journey and is happy to share our experience over a video call and a cup of chai. Let's connect.

Frequently Asked Questions

How long does a Sitecore to Umbraco migration take?

For a mid-sized website with a few hundred pages, two or three languages, and a handful of integrations, a Sitecore to Umbraco migration typically takes around two months end to end. Smaller marketing sites can be done in four to six weeks. Enterprise sites with heavy personalization and commerce can run longer or more. Content complexity, not page count, usually decides the timeline.

How much cheaper is Umbraco compared to Sitecore?

Across the engagements we have delivered, clients typically see a forty to seventy percent reduction in total cost of ownership over a three-year horizon when moving from Sitecore to Umbraco. The savings come from zero per-user and per-server licensing on the Umbraco core platform, a lighter infrastructure footprint, and lower developer-rate requirements. Umbraco Cloud and paid add-ons remain, but the predictable pricing model is far friendlier.

Will our SEO rankings be affected during the migration?

Not if the migration is done well. The two things that matter most are a comprehensive 301 redirect map that preserves every legacy URL, and faithful migration of meta titles, descriptions, canonical URLs, Open Graph tags, and the XML sitemap. On our engagements, impressions typically hold steady through go-live and long-tail rankings recover within four to six weeks of any minor wobble.

Can Umbraco handle multilingual websites as well as Sitecore?

Yes, comfortably. Umbraco has first-class multilingual and multisite support built into the core back office, with language variants, fallback rules, and dedicated culture-aware rendering. Our clients regularly run two to eight languages on a single Umbraco install. The back office is often simpler for editors than Sitecore's equivalent.

Do we need to rebuild all our custom Sitecore features from scratch?

Not all of them. Core patterns like personalization, forms, search, workflow, caching etc. all have well-supported Umbraco equivalents, either in the core or via community and commercial packages. Deep custom integrations usually need to be reimplemented on the Umbraco side, but the modern .NET stack makes this faster than the equivalent work on Sitecore. Our architects assess every custom feature during discovery and recommend the right path for each.

What happens to our existing content during the migration?

Content is exported from Sitecore, transformed through an automated and idempotent migration pipeline, and loaded into Umbraco Document Types that mirror the agreed information architecture. Media is reorganized, rich text is cleaned, multilingual variants are preserved, and every item goes through automated validation. Editors see the new content long before go-live so they can spot-check and sign off.

How do you ensure there is no downtime at go-live?

We run the Umbraco build in parallel with the live Sitecore site throughout the project. On go-live night, a final delta migration brings across any content changed in the freeze window, validation runs green, and the DNS cutover happens during the quietest traffic hours. The redirect map handles every legacy URL from the first second. A seventy-two-hour hyper care rotation watches logs, analytics, and editor feedback.

Why choose Giriraj Digital for a Sitecore to Umbraco migration?

We are an Umbraco Platinum Partner, the first in India. Our team has delivered Sitecore to Umbraco migrations across financial services, education, and large publisher sites, with a strong track record of on-time go-lives and preserved SEO. If you would like to compare notes on your own migration, we are happy to set up a short call. Reach us at girirajdigital.com or drop a line to our team.

Girirajdigital Newsletter
Join 1500+ people for our free Newsletter

Sign up now to receive exclusive updates, industry insights, and special offers directly to your inbox.

Back To Top