Moving an Umbraco 13 site to 17: a practical migration plan
Plan an Umbraco 13 to 17 upgrade around packages, backoffice extensions, content conversion, UTC dates and a repeatable rehearsal on a database copy.
The difficult part of an Umbraco upgrade is usually the code and content surrounding the CMS. A site can boot successfully while a custom property editor, an old rich-text value or a scheduled publishing date still needs attention.
These are the areas I focus on when working on a 13-to-17 migration. They are a planning guide, rather than a promise that every site can follow an identical sequence.
Inventory the site before changing it
Start with a list of packages, custom property editors, dashboards, API controllers, notification handlers and scheduled jobs. Record what each does and who uses it. An unused package may be removable; a small editor that stores business-critical content needs careful treatment.
Include the data formats, not just NuGet references. Block editors, pickers, rich text and custom JSON can outlive the editor that originally wrote them. Capture representative raw values alongside screenshots of the current editing and rendering experience.
Check every dependency for an Umbraco 17-compatible release. Core compatibility does not establish package compatibility, and a package that compiles may still need a data conversion.
Treat the platform and backoffice as separate work
Umbraco 13 runs on .NET 8; Umbraco 17 targets .NET 10. Prepare the corresponding SDK, hosting runtime and build environment. The Umbraco 17 release overview explains the platform changes.
The AngularJS backoffice ended with version 13. Custom AngularJS views cannot simply be copied into the newer backoffice. Rebuild or replace them using the current extension model; my Lit and Vite package notes describe how I approached that in God Mode and Audit Log Viewer.
For server code, work through compiler errors and changed APIs deliberately. Pay particular attention to authentication, custom Management API endpoints, service lifetimes and async operations. Removing an obsolete API call without understanding its previous behaviour can create a subtler failure later.
Read the changes in every skipped major
A supported direct core upgrade path does not remove the changes introduced in intermediate releases. Read the version-specific upgrade details for 17 across all versions you cross, and check the guidance for your starting patch and database provider.
Do not assume you must deploy every intermediate major, or that one universal jump works for every package combination. Decide the route after checking those prerequisites and rehearsing it with the site’s actual data.
Rich text deserves its own review. TinyMCE’s removal in 16 and the move to Tiptap affect editor configuration and stored content. Check links, embedded content, custom formats, macros and any bespoke HTML handling. Legacy Grid and Nested Content values also need an explicit plan where they remain in use.
I compare both raw content and rendered output. A value being present in the database does not prove the new editor can read and save it without loss.
Protect keys and content before schema changes
Stable document type, composition, property and element keys are part of the migration. Recreating a type with the same display name does not necessarily preserve its relationship to existing values.
When synchronising schema, review a report before importing it. If an import removes or renames a property, capture and transform its old values before that operation makes them inaccessible. Include drafts, published versions and language variants in the exercise.
Keep schema files and database migrations consistent. A successful startup conversion can be undone by a later schema import that restores an old configuration. My block label migration example is a useful small illustration of that problem.
Check the system-date migration
Umbraco 17 stores system dates in UTC and migrates existing dates. Before the first upgraded startup, establish the timezone used by the original server. This is especially important if the rehearsal or production upgrade runs on a machine in a different timezone.
The documented Umbraco:CMS:SystemDateMigration:LocalServerTimeZone setting lets you specify the source timezone. Use the historic server’s appropriate timezone identifier, verified for your hosting environment. Your laptop’s timezone or the website’s audience location is not sufficient evidence.
After conversion, inspect creation dates, audit entries and scheduled publishing around daylight-saving boundaries. Verify display as well as storage; UTC values still need appropriate presentation to editors.
Rehearse the complete deployment
Use a consistent database backup and the matching media and configuration. Keep the rehearsal isolated from live email, webhooks, search indexing and scheduled integrations. Record how long migrations take and retain their logs.
Deploy a clean published application. An overlay deployment can leave obsolete assemblies or App_Plugins assets behind, which makes debugging a migration needlessly confusing.
My acceptance checks include:
- Sign in with representative backoffice roles, including restricted users.
- Open, edit, save and publish representative content in each language.
- Inspect rich text, blocks, media, forms and custom editors.
- Exercise search, redirects, external integrations and scheduled publishing.
- Restart the application and confirm migrations and jobs behave correctly again.
- Compare important public URLs, metadata and rendered HTML with the old site.
Make rollback a real operation
Preserve a matching set of database, media, application and configuration backups. Once a migration changes the database, deploying the old binaries alone is not a reliable rollback. Umbraco’s downgrade documentation explains why migrations generally move forwards.
Before cutover, decide how you will handle content changes made during the deployment window. Rehearse restoring the previous environment as well as upgrading the next one. The useful deliverable is a repeatable procedure with evidence that editors can still do their work.