Migration
How do you migrate from Umbraco to Sanity?
Short answer
An Umbraco to Sanity migration is a script you write, because Sanity publishes no Umbraco importer, course or guide (Sanity migration skill, October 2026). Umbraco 13 exports through its opt-in Content Delivery API (application programming interface), which returns rich text as HTML by default (Umbraco, October 2026). Umbraco 13 reaches end of life on 14 December 2026 (Umbraco, October 2026).
- Umbraco 13 end of life
- 14 December 2026No security patches or updates after that date. XLTS adds 6, 12 or 24 months of security patches only, quoted on requestSources: Umbraco (Umbraco 13 End-of-Life (EOL), Extended Long-Term Support for Umbraco 13)
- Export route on Umbraco 13
- Content Delivery API, opt-inOnce enabled, all published content is public by default; drafts need the Preview header and an API key. The Management API starts at Umbraco 14Sources: Umbraco Docs (Content Delivery API (Umbraco 13), Content Delivery API); Umbraco (Umbraco 14 Release Candidate)
- Sanity tooling for Umbraco
- No Umbraco course, MCP path or skill guideSanity's migration skill says to adapt the WordPress, Drupal, Webflow or AEM pattern for other page-builder systemsSources: Sanity (You'll need a CMS eventually. Let your agent set it up., sanity-migration skill (SKILL.md on GitHub), sanity-migration skill references (GitHub))
- Redirect history
- The umbracoRedirectUrl tableUmbraco logs every URL a publish changed and answers it with a 301; export it, because a crawl of the live site can't find those old URLsSource: Umbraco Docs (URL Redirect Management)
Deploi’s call
Move from Umbraco 13 to Sanity section by section, reading through the Content Delivery API, and buy XLTS for the overlap instead of racing 14 December 2026. If the deadline is your only reason to move, upgrade to Umbraco 17 instead, because the deadline forces a version upgrade, not a new CMS.
PhaseMove from Umbraco to Sanity section by section when
- The replatform decision is made and the site is too large to cut over in one move, such as several sections, languages or sites in one Umbraco install.
- You can enable the Content Delivery API (application programming interface) on Umbraco 13 and rerun the import until cutover, so editors keep publishing in Umbraco while each section moves.
- Extended Long-Term Support (XLTS) covers Umbraco 13 for the months both systems run, so unmigrated sections keep getting security patches after 14 December 2026; Umbraco quotes it on request as of October 2026.
- Your editors fit Sanity's five Growth roles, because custom roles are Enterprise only as of October 2026.
StayStay on Umbraco and upgrade to Umbraco 17 while
- The 14 December 2026 end of life is your only driver, because an upgrade to Umbraco 17 meets that deadline. Umbraco lists Umbraco 17, the current long-term support (LTS) release, as security-only from 27 November 2027 and at end of life on 27 November 2028, as of October 2026.
- Members, Umbraco Forms or Umbraco Commerce carry the site and nothing funds replacing them, so a move would rebuild logins, forms and checkout before it moved a page.
Does an Umbraco to Sanity migration have to finish by 14 December 2026?
An Umbraco to Sanity migration doesn't have to finish by 14 December 2026, because Extended Long-Term Support (XLTS) keeps Umbraco 13 patched while sections move. After that date Umbraco ships no security patches or updates for Umbraco 13, though sites keep running (Umbraco, Umbraco 13 End-of-Life, October 2026). XLTS covers the overlap on these terms (Umbraco, Umbraco 13 XLTS, October 2026):
- Length. 6, 12 or 24 months.
- Start. The day after end of life.
- Cover. Security patches only.
- Price. Quoted on request; Umbraco publishes no price.
So a phased migration can run past December, with unmigrated sections patched and editors still publishing in Umbraco. If the deadline is your only reason to leave, the shorter road is an upgrade to Umbraco 17, the most recent long-term support (LTS) release (Umbraco; Umbraco Docs, October 2026), and whether to leave Umbraco at all is weighed on its own page.
How do you get content out of Umbraco 13?
Get content out of Umbraco 13 through its Content Delivery API (application programming interface), the built-in route that returns content as JSON. It's opt-in, and drafts need a Preview header plus an API key (Umbraco Docs, Content Delivery API for Umbraco 13, October 2026). The Management API, which can control everything in Umbraco, arrived with Umbraco 14's new backoffice (Umbraco, Umbraco 14 Release Candidate, October 2026), so it's the richer route only on 14 or later.
| Export route | What you get | Trade-off |
|---|---|---|
| Content Delivery API | Published nodes as JSON, with routes, cultures and blocks | Skips member-protected pages by default; no macro output |
| Management API | Access to everything in Umbraco | Umbraco 14 and later only; needs a backoffice token |
| Database read | Every table, including redirect history | Blocks stored in Umbraco 13's legacy format; you parse them |
How do Umbraco Document Types, compositions and languages map to Sanity?
Umbraco Document Types map to Sanity document types, so compositions, the content tree and languages become fields, objects or references on them. In Umbraco every item has a type: Document Types for pages, Media Types for media, Member Types for member profiles (Umbraco Docs, Content Types and Structure, October 2026). Compositions share groups of properties across multiple Document Types (Umbraco Docs, October 2026). Model what content means, not how one page shows it (Sanity Docs, October 2026). Language Variants vary a node by culture (Umbraco Docs, Language Variants, October 2026), which maps to Sanity's document-level or field-level localization (Sanity Docs, Localization, October 2026).
| Umbraco structure | Sanity equivalent | Migration note |
|---|---|---|
| Document Type | Document type | Drop template-only types |
| Composition | Shared object type or fields | Define once, reuse |
| Content tree | Parent reference and slug | Rebuild paths from routes |
| Media Type | Image or file field | Alt text moves onto the field |
| Member Type | None | Profiles go to an identity service |
| Language Variants | Document-level or field-level localization | Shared properties suit field-level |
| Dictionary Item | A strings document per language | One value per language per key |
How do Umbraco Block List and Block Grid become a Sanity page builder?
Umbraco Block List and Block Grid become a Sanity array of object types, one object type per Element Type you keep. Both Umbraco editors build each block from an Element Type for content, plus an optional one for settings (Umbraco Docs, Block List, October 2026). A Sanity page builder is an array of object or reference types you define, with no pre-built blocks (Sanity Docs, structured content for page building, October 2026). Block Grid adds column spans, row spans and areas that nest blocks inside blocks (Umbraco Docs, Block Grid, October 2026). Keep the content, not the grid, so the next redesign doesn't have to untangle it.
| Umbraco block structure | Sanity equivalent | Migration note |
|---|---|---|
| Content Element Type | Object type | Name it for what it holds |
| Settings Element Type | A few layout fields, or none | Keep deliberate choices only |
| Block List | Array of object types | Order carries over |
| Block Grid spans | Front-end layout | Not stored as content |
| Block Grid areas | Nested array | Only where nesting means grouping |
| Block reused across pages | Reference to a document | Objects stay in one document |
How does Umbraco rich text become Portable Text?
Umbraco rich text becomes Portable Text through a converter you configure, because Umbraco's Rich Text Editor returns HTML (Umbraco Docs, Rich Text Editor, October 2026). Portable Text is Sanity's presentation-agnostic block content (Sanity Learn, October 2026). htmlToBlocks from @portabletext/block-tools turns headings, lists and paragraphs into Portable Text blocks by default; images and custom objects need rules you write (Sanity Learn, Converting HTML to Portable Text, October 2026).
Three Umbraco details change the script:
- HTML or JSON. The Content Delivery API (application programming interface) outputs HTML unless you set
RichTextOutputAsJson, and Umbraco says JSON "supports the routing of internal links better than HTML does" (Umbraco Docs, Content Delivery API, October 2026). Choose JSON for a multi-site install; you then write the converter for its structure instead of usinghtmlToBlocks(Deploi's judgment). - Macros. The API doesn't execute or output macros in rich text (Umbraco Docs, October 2026), so find them in a database copy and map each to an object type.
- Blocks in rich text. Each block that editors can insert into the Rich Text Editor (Umbraco Docs, October 2026) needs its own object type in the Portable Text array.
Log every element the converter drops, because each one is a schema decision.
What happens to Umbraco media, URLs and redirects?
Umbraco media becomes Sanity image and file assets, and every Umbraco URL that changes needs a Sanity redirect document. Three jobs carry this:
- Media. Sanity's import tool takes a
_sanityAssetproperty where a reference would go and uploads the file for you (Sanity Docs, Import data, October 2026). Store each Umbraco media ID in a field, so a rerun can match assets it already uploaded (Deploi's judgment). - Crawl. Crawl the live site to record every page that exists; Sanity's course says a re-platformed front end "should not create a new link structure without appropriate redirects" (Sanity Learn, re-platforming course, October 2026).
- Redirect history. Export Umbraco's own redirect history. Each time a publish changes a URL, Umbraco writes a row to the
umbracoRedirectUrltable and answers the old URL with a 301 (Umbraco Docs, URL Redirect Management, October 2026). A crawl can't find those old URLs, because nothing links to them anymore, so a migration that skips the table drops redirects Umbraco has been serving.
Keeping search engine optimization (SEO) through a move to Sanity covers the redirect map, redirect limits and sitemap dates.
What replaces Umbraco users, Members, Forms and packages?
Umbraco backoffice users become Sanity project members with roles, while Members, Umbraco Forms and most packages move to services outside Sanity. Umbraco's default user groups are Administrators, Editors, Sensitive Data, Translators and Writers, and Writers aren't allowed to publish directly (Umbraco Docs, Users, October 2026). Sanity's Growth plan has five built-in roles, and custom roles are Enterprise only as of October 2026 (Sanity Docs, Roles and permissions; Sanity pricing). Umbraco's start nodes limit a group to part of the tree; Growth roles cover every document, so those limits need custom roles. Members are site visitors who register and log in (Umbraco Docs, Members, October 2026), so they need an identity service. Export Umbraco Forms entries (Umbraco, Umbraco Forms, October 2026) before you rebuild forms on a form service.
| Umbraco | Sanity on Growth | Gap |
|---|---|---|
| Administrators | Administrator | None |
| Editors | Editor | Start nodes need custom roles |
| Writers | Contributor | Contributor edits drafts; an Editor publishes |
| Translators | Contributor or Editor | No language-scoped role below Enterprise |
| Members | None | Logins move to an identity service |
| Umbraco Forms | None | Export entries, then rebuild on a form service |
What is the step-by-step plan for an Umbraco to Sanity migration?
An Umbraco to Sanity migration runs in seven steps, and the import script runs many times. Sanity has no Umbraco path: neither its Model Context Protocol (MCP) server's guided migrations (Sanity blog, October 2026) nor its migration skill's source guides cover Umbraco (Sanity migration skill, October 2026). So the plan adapts the general migration method: rerun the script against current content, reusing each Umbraco node ID as the document ID (Sanity Learn, October 2026).
Migrating Umbraco 13 to Sanity
- Inventory. Count nodes per Document Type, crawl live URLs, export the redirect table, list packages and forms. Owner: developer.
- Open the export. Enable the Content Delivery API (application programming interface) with public access off. Owner: developer.
- Model. Define schema types for what content means, one object type per Element Type you keep. Owner: developer and content lead.
- Script the import. Switch off webhooks (Sanity Docs, October 2026) and rerun the import safely with
--replace. Owner: developer. - Convert rich text and media. Map macros and rich text blocks to object types, upload media, log drops. Owner: developer.
- Rebuild redirects. One redirect document per changed path and per redirect row. Owner: search lead.
- Validate and cut over. Run
sanity documents validate(Sanity Learn, October 2026), check every old URL, then switch one section at a time. Owner: developer.
Deploi’s point of view
- Where we disagree
- The usual advice treats the export as the hard part of leaving Umbraco. Umbraco 13 already serves its content as JSON, block editors included, so getting content out is the easy part. The work sits elsewhere: rich text stored as HTML, macros the API won't output, member-protected pages the API skips by default, and the redirect history in umbracoRedirectUrl, which a crawl of the live site can't find because nothing links to those old URLs anymore.
- What we’ve seen
- Our view of Umbraco rests on its documentation and public sources. The import discipline we'd bring comes from deploi.ca's own Sanity release of September 2026, which moved its live FAQ answers to shorter URLs. Its runbook made every Sanity script a dry run unless passed an apply flag, skipped any document edited since the snapshot, listed the counts to expect before anything was applied, and called for a dataset export first, so a restore was one import with --replace.
- What we'd tell you to do first
- Before any schema work, export three lists from Umbraco 13: every published node with its Document Type and route, the umbracoRedirectUrl table, and every installed package, form and Member Type. The first sizes the job, the second becomes your redirect documents, and the third lists what Sanity won't do for you.
- Where we would push back
- On switching the Content Delivery API on in production with its defaults. Enabled, it makes all published content public, so turn public access off and use an API key, or export from a copy of the production database.
When this answer changes
- Sanity adds an Umbraco guide to its migration skill, its MCP server's guided paths or Sanity Learn
- Umbraco changes the Content Delivery API's rich text output or its public access default
- Umbraco changes Umbraco 13 XLTS terms or publishes a price
- Umbraco moves Umbraco 13's 14 December 2026 end-of-life date
- Sanity offers custom roles below the Enterprise plan
Sources
Every source opened and checked on 25 October 2026.
- Umbraco Docs, Content Delivery API (Umbraco 13)
- Umbraco Docs, Content Delivery API
- Umbraco, Umbraco 13 End-of-Life (EOL)
- Umbraco, Extended Long-Term Support for Umbraco 13
- Umbraco, Long-term Support (LTS) and End-of-Life (EOL)
- Umbraco Docs, Management API
- Umbraco, Umbraco 14 Release Candidate
- Umbraco Docs, Content Types and Structure
- Umbraco Docs, Block List
- Umbraco Docs, Block Grid
- Umbraco Docs, Rich Text Editor
- Umbraco Docs, Language Variants
- Umbraco Docs, Dictionary Items
- Umbraco Docs, URL Redirect Management
- Umbraco Docs, Users
- Umbraco Docs, Members
- Umbraco Docs, Find Your Upgrade Path
- Umbraco, Umbraco Forms
- Sanity Learn, Re-modelling your existing content
- Sanity Learn, Migrating without downtime
- Sanity Learn, Converting HTML to Portable Text
- Sanity Docs, How to use structured content for page building
- Sanity Docs, Import data
- Sanity, You'll need a CMS eventually. Let your agent set it up.
- Sanity, sanity-migration skill (SKILL.md on GitHub)
- Sanity, sanity-migration skill references (GitHub)
- Sanity Docs, Localization
- Sanity Docs, Roles and permissions
- Sanity, Plans that scale with you
- Sanity Learn, Deterministic and consistent IDs