A static block’s save output is stored in the post, and changing it invalidates every existing instance unless the old shape is still declared.
const v1 = {
attributes: { /* the OLD shape */ },
save: ({ attributes }) => <div className="notice">...</div>,
migrate: (attributes) => ({ ...attributes, tone: 'info' }),
}
registerBlockType('turkerdev/notice', {
save: ({ attributes }) => <div className="td-notice">...</div>,
deprecated: [v1],
})
Without the deprecation the editor shows “this block contains unexpected or invalid content” on every existing post, and the recovery options all lose something. The array grows with every markup change and is never removed, which is the honest cost of static blocks. migrate is what converts old attributes to the new shape, and it runs once when the post is next opened and saved — so a site whose posts are never re-saved keeps the old markup indefinitely.