Structured Content 2022: Join our conference to explore fresh perspectives on content and digital experiences →

How to migrate from blocks spans to block children

We are resolving a few issues with the way block content is structured. Unfortunately, this is a breaking change and will thus require a migration. There are a couple of steps involved:

Update your frontend modules to support both the new and the old format

There are a couple of official ways of rendering block content - if you have a Javascript app and are using block-content-to-react or block-content-to-html, please upgrade those to the latest versions. If you are using the PHP client, update that to the latest version.

Update schema

Unless you have customized the block type within your schema, you shouldn't have to do anything. However if you have customized it with allowed marks, or special rules for the span, you must ensure that the block type schema definition has the following new structure:

See the updated block and span documentation for more information.

Migrate your data

All documents containing one or more block fields must be migrated to the new structure. We have written a script that does this automatically for you. This can be executed with the command line tool npx , which has been shipping with npm from version 5.2.0:

cd <your sanity studio project folder>
npx -p sanity-io/migrations block-spans-to-children

Update your studio

Run sanity upgrade in your studio to get the latest modules which includes a new version of the block editor. Running this new version without first migrating your data will yield a warning telling you that data needs migration.

Technical details

Note: This isn't mandatory reading unless you want to understand the changes to the data structure.

Previously, blocks had a key named spans which we're renaming to children. This is more in line with how most people think of nodes within their data model. We're also changing the way rich marks are represented. Instead of simply being attributes on each child, they are now pointers to a mark definition on a per-block basis. This helps to prevent duplication of data and also makes it easier to nest nodes in trees.

Old structure:

{
  "_key": "d3bf4f7519f3",
  "_type": "block",
  "style": "normal",
  "spans": [
    {"_type": "span", "marks": ["em"], "text": "Headless CMS?"},
    {"_type": "span", "marks": [], "text": " Check out "},
    {"_type": "span", "marks": [], "text": "Sanity", "link": {"href": "https://sanity.io"}},
    {"_type": "span", "marks": [], "text": ", it's pretty neat"}
  ]
}

New structure:

{
  "_key": "d3bf4f7519f3",
  "_type": "block",
  "style": "normal",
  "markDefs": [{
    "_type": "link",
    "_key": "someKey",
    "href": "https://sanity.io"
  }],
  "children": [
    {"_type": "span", "marks": ["em"], "text": "Headless CMS?"},
    {"_type": "span", "marks": [], "text": " Check out "},
    {"_type": "span", "marks": ["someKey"], "text": "Sanity"},
    {"_type": "span", "marks": [], "text": ", it's pretty neat"}
  ]
}

Was this article helpful?