A year and a half ago I wrote about upgrading from Umbraco 8 to 13, and how it was easier than expected. Well, here we are again. If you've been anywhere near the Umbraco community since V14 dropped, you'll know that the backoffice got a complete rewrite (hello, Bellissima!), and that there are many who still fear upgrading. So here's the secret: I jumped straight from 13 to 17, and honestly? Nothing much broke!
In this blog we'll cover why and how I upgraded this site to Umbraco version 17, a full checklist of everything I touched code-wise, the launch itself, and how I was able to do it in around two hours time... let's go!
The Goal
There are numerous good reasons to keep your site running on the latest version of Umbraco, but for me the two main selling points are security & maintainability. Umbraco 13 will be going End of Life by December this year, and I wanted to make sure that I kept the site up-to-date, running on the Long Term Supported version of the CMS to keep everything running smoothly.
Besides security & maintainability, I also had several ideas in mind involving changing the look and feel of the site, and I wanted to make sure that the site was running on a solid foundation before I got started on that.
Getting Started
Before I touched any code, I wanted to create a clear checklist of what needed to be done in order to get the site from its early 13.5.2 state, all the way to the latest to-date version 17.5.3. Of course I could have written this upgrade spec manually... but it's 2026, so I asked my trusty friend Claude Code to analyze my codebase and do this for me instead! The tasklist consists of the following five sections:
Upgrade to Umbraco 17: Implementation Tasks
1. Pre-upgrade hygiene on V13
- [ ] 1.1 Delete unused data types "Media Picker (legacy)" and "Multiple Media Picker (legacy)" in the backoffice; confirm their .uda files are removed from `umbraco/Deploy/Revision` on commit
- [ ] 1.2 Delete `Views/Partials/grid/` and the empty `Views/MacroPartials/` folder
- [ ] 1.3 Remove the commented-out RenderMacro block from `Views/ContactPage.cshtml`
- [ ] 1.4 Remove the Smidge `@addTagHelper`/`@inject` lines from `Views/_ViewImports.cshtml` and `Infrastructure/Components/_ViewImports.cshtml`
- [ ] 1.5 Bump all nine Umbraco packages in `UmbracoProject.csproj` to latest 13.x (Umbraco.Cms 13.15.0 etc.), build and run locally
- [ ] 1.6 Push the 13.15.0 state to Cloud Live; verify site + backoffice
2. Cloud environment preparation
- [ ] 2.1 Add a second Cloud environment (Development) in the portal
- [ ] 2.2 Take a database backup of Live from the portal
- [ ] 2.3 Switch environment runtime(s) to .NET 10 (Configuration → Advanced → Runtime Settings), non-live first
3. Local major upgrade (fresh clone + prod DB copy)
4. Local verification
5. Cloud rollout
After agreeing with the plan and the pre-upgrade hygiene, I manually tackled task 1.1, had Claude do 1.2 through 1.5, made sure everything was running smoothly on the latest version of V13, and then did 1.6! Total time spent so far? 30 minutes! 🕧
From V13 to V17
Now that my site was running on the latest version of V13, I needed to prepare the Umbraco Cloud environment to have a Development environment that I could set to target .NET 10, in order to do a trial-run on the upgrade before pushing it to live. Luckily the Cloud Portal makes this incredibly easy. Pressing 'Configure Environments', adding a development copy of the live site, having Umbraco Cloud configure all the Deploy settings, and cloning that copy of the site down took another 20 minutes at best! 🕐
Attachment 1. Configuring a Development environment before the Live environment
With the development site running locally, it was time to proceed with the actual upgrade! This site relies entirely on official Umbraco packages on top of my own back-end, resulting in a checklist that is based entirely on the upgrade paths provided by the Umbraco Docs, and Microsoft's own .NET 8 -> 10 upgrade path. Because of that I had a lot of faith to have Claude Code do the full migration for me, and verify its own results... and so it did!
3. Local major upgrade (fresh clone + prod DB copy)
- [ ] 3.1 Clone the left-most environment fresh; restore a copy of the production database locally; install .NET 10 SDK
- [ ] 3.2 Set `<TargetFramework>net10.0</TargetFramework>`; bump surviving packages to 17.x (see version table in spec.md); remove `Umbraco.Cloud.Identity.Cms` and `Umbraco.Cloud.Cms.PublicAccess`; align ICU/Razor csproj properties with the V17 Cloud template
- [ ] 3.3 Delete `umbraco/Licenses/*.lic`; add Deploy/Forms 17 license configuration to `appsettings.json`
- [ ] 3.4 Update `Program.cs` to the V17 template (drop `UseInstallerEndpoints()`, keep sitemap/rss routes and `/static` provider)
- [ ] 3.5 Clean settings: remove `RuntimeMinification` (Development + Production json) and `Global:SanitizeTinyMce`; verify `NoNodesViewPath`; regenerate/remove stale `appsettings-schema.*.json`
- [ ] 3.6 Delete `App_Plugins/UmbracoId/`
- [ ] 3.7 Wipe `Models/Generated/*`, boot to regenerate via ModelsBuilder, fix all compile errors in `Infrastructure/` and `Views/`
- [ ] 3.8 Boot with `UpgradeUnattended: true` against the prod DB copy — verify migration chain completes (TinyMCE→Tiptap, UTC dates); rebuild Examine indexes
4. Local verification
- [ ] 4.1 Backoffice: login, edit blog post (Block List + Tiptap RTE), media library, Forms section
- [ ] 4.2 Frontend: homepage, blog overview (search `?query=`, tag `?tag=`, pagination), blog detail (RichText/Gist/Gallery blocks), about, contact, 404, `/sitemap.xml`, `/rss`, `/static` + `/dist` assets
- [ ] 4.3 QA a sample of RTE-heavy posts for Tiptap migration artifacts; review the migrated RTE data-type toolbar config
- [ ] 4.4 Verify date rendering/ordering after UTC migration: `PublicationDate` sort, RSS `pubDate`, sitemap `LastMod`
As the checklist would suggest, Claude configured the site to target .NET 10, bumped all package dependencies to V17, cleaned up the old license files and replaced them with their V17 counterparts, updated the Program.cs file, removed settings that no longer exist, and wiped the outdated ModelsBuilder models so they'd regenerate after an unattended Umbraco upgrade. This entire process only resulted in a handful of compiler errors, which Claude automatically detected and resolved!
What surprised me the most was that the automatic data migration of Rich Text Editors (RTE) happened smoothly without me even noticing! Umbraco 17 stepped away from using TinyMCE in favor of Tiptap, where I expected that I had to take at least some manual configuration steps in order to have Umbraco migrate all my elements with an RTE to be compatible with Tiptap... but nope, the Umbraco upgrade process did it all for me! It is worth keeping in mind that the size of this site is very manageable which resulted in very little resource usage during the migration. If you are working on a client's site that has thousands of RTE fields, especially when nested in Block Lists/Grids, resource usage goes up rapidly, so make sure to consult the official documentation for Planning Major Upgrades Safely for Live Environments!
After going through all the changes in the back-office, verifying all the front-end pages, and verifying if features like search, tags, sitemap and the RSS feed still worked, we were in a good place! Time spent? An hour and a half in total! 🕜
The V14 Backoffice Question
To address the elephant in the room, did the backoffice rewrite bite me? The answer is no! Since I had zero custom backoffice integrations there was nothing that needed to change in regard to AngularJS to Lit & Typescript rebuilds.
The reason why I mention this: If your site does rely on V13 community driven packages, or custom backoffice work, be mindful that the heavy parts of the upgrade are in there. Don't expect to be able to upgrade a client's site that heavily relies on these custom packages within the same timespan as I was able to!
Pushing & Launching
With everything running smooth as butter on my local machine, it was time to push it to the Cloud Development environment. That brings me to the final chapter of the checklist.
5. Cloud rollout
- [ ] 5.1 Push to the non-live environment; confirm Deploy schema import + migrations succeed; repeat verification 4.1–4.4
- [ ] 5.2 Content freeze; deploy to Live via the portal; verify on https://cornehoskam.com
- [ ] 5.3 Rebuild Examine indexes on Live; smoke-test search
- [ ] 5.4 Monitor Cloud logs for several days; keep DB backup until stable; decide whether to remove the temporary environment
After pushing all my local changes to Umbraco Cloud, and waiting for it to complete its build & Deploy import process, the site looked... exactly as it did before! For a brief moment I was somehow expecting longer loading times and upgrade spinners, or perhaps even expected something to fail, but no, the site rendered everything exactly as it did before, like nothing even happened! Almost wondering if the upgrade even went through, I went to the backoffice, but sure enough it was running now on Umbraco V17!
One last verification round on the Development site, a quick configuration change in the Cloud portal to change the runtime on the Live site from .NET 8 to .NET 10 as well, and we were ready to push the changes to Live! Total time spent? Two hours! 🕑
Wrapping up
And that completes a full Umbraco V13 to V17 upgrade on Umbraco Cloud in a mere two hours time! Umbraco has been promising smoother upgrades when going from Major to Major versions over the last few years, and they have certainly delivered.
The big takeaway? A straight jump from 13 to 17 is absolutely doable, and honestly a lot less scary than the community chatter around the V14 rewrite might have you believe. Just keep in mind the caveat from earlier: my site leans entirely on official Umbraco packages with no custom backoffice work, which is exactly why it went so smoothly. If you're sitting on a pile of V13 community packages or custom AngularJS integrations, your mileage will vary, so plan accordingly!
What struck me the most though was the difference two years makes. Last time I did the whole thing by hand, this time I had Claude Code analyze the codebase, write the upgrade spec, and handle the bulk of the migration while I verified along the way. Same pleasant surprise, a fraction of the effort. Turns out I'm two-for-two on Umbraco upgrades being easier than expected! 😅
With the foundation now solid and running on the latest LTS, I can finally start playing with those ideas I had for freshening up the look and feel of the site... but that's a story for a future blog!
If you've made it all the way to the bottom, I would like to thank you for your interest, and if there is anything I've mentioned that you'd like to learn more about feel free to contact me over at my socials available at the Contact page! Until next time. 😊☕