Serialization

Serialization is saving the state of your workspace so that it can be loaded back into the workspace later. This includes serializing the state of any blocks, variables, or plugins that you want to save. You can convert all of the data you need to save into a text-based format for easy storage, and then load that data back into a fully functional workspace later.

Blockly provides two formats for this data: JSON and XML. We recommend using the JSON system for new projects, and encourage older projects using XML to upgrade. The XML system is the legacy save format. It will not be removed, but it will not receive new features.

JSON system

The JSON serialization system is made up of multiple serializers. There are built-in serializers for blocks and variables, and you can also register additional serializers. Each serializer is responsible for serializing and deserializing the state of a particular plugin or system.

Saving and Loading

Workspaces

You can serialize or deserialize the state of an entire workspace by calling the save and load methods on the workspaces namespace.

const state = Blockly.serialization.workspaces.save(myWorkspace);
Blockly.serialization.workspaces.load(state, myWorkspace);

These calls serialize or deserialize all of the individual systems (represented by serializers) which are registered with the workspace.

Individual blocks

You can serialize or deserialize individual blocks by calling the save and append methods on the blocks namespace.

const blockJson = Blockly.serialization.blocks.save(myBlock);
const duplicateBlock =
    Blockly.serialization.blocks.append(blockJson, myWorkspace);

Individual systems

You can serialize or deserialize individual systems (e.g. blocks, variables, plugins, etc) by constructing the associated serializer, and calling its save and load methods.

// Saves only the variables information for the workspace.
const serializer = new Blockly.serialization.variables.VariableSerializer();
const state = serializer.save(myWorkspace);
serializer.load(state, myWorkspace);

Deserialization order

The JSON system has an explicit deserialization order, which makes it easier to prevent duplicating state within a save.

When Blockly.serialization.workspaces.load is called, serializers are given state to deserialize in order of priority. This is explained further in the Serializers section, and its purpose is to allow serializers to depend on state from other systems.

The order for deserialization of built-in serializers is:

  1. Variables are deserialized.
  2. Blocks are deserialized. Individual stacks/top-level blocks are deserialized in an arbitrary order.
    1. Type is deserialized. This triggers the block’s init method, mixes in extensions, etc.
    2. Attributes are deserialized. This includes properties that can apply to any block. For example: x, y, collapsed, disabled, data, etc.
    3. Extra state is deserialized. See the Extensions and Mutators documentation for more info.
    4. The block is connected to its parent (if one exists).
    5. Icons are deserialized. Individual icons are deserialized in an arbitrary order.
    6. Fields are deserialized. Individual fields are deserialized in an arbitrary order.
    7. Input blocks are deserialized. This includes blocks connected to value inputs and statement inputs. Individual inputs are deserialized in an arbitrary order.
    8. Next blocks are deserialized.

When to save extra state

For blocks, if you have something lower in the order that depends on something higher in the order, you should duplicate that data and add it to your extra state.

For example, if you have a field that only exists if a next block is connected, you should add info about that next block to your extra state, so the field can be added to your block before the field’s state is deserialized.

However, if you have an input that only exists if a field has a certain value, you do not need to add info about the field to your extra state. This is because the state of your field will be deserialized first, and when it is, you can add the input to your block. Usually adding the input will be triggered by a validator.

Note that the rule about duplicating state should also take into account that block stacks, icons, fields, and input blocks are deserialized in an arbitrary order. For example, if you have one field B that only exists if another field A has a certain value, you should add info about A to your extra state in case B is deserialized before A.

Block hooks

For information about how to add extra serialization to blocks, see the Extensions and Mutators documentation.

Field hooks

For information about how to serialize fields, see the Custom fields documentation.

Serializer hooks

The JSON system allows you to register serializers which serialize and deserialize some state. Blockly's built-in serializers take care of serializing information about blocks and variables, but if you want to serialize other information you'll need to add your own serializer. For example, workspace-level comments are not serialized by default by the JSON system. If you want to serialize them, you will need to register an additional serializer.

Additional serializers are often used to serialize and deserialize the state of a plugin.

Blockly.serialization.registry.register(
    'workspace-comments',  // Name
    {
      save: saveFn,      // Save function
      load: loadFn,      // Load function
      clear: clearFn,    // Clear function
      priority: 10,      // Priority
    });

When you register a serializer you must provide several things:

  • A name for the serializer, which the data is also saved under.
  • A function to save the state of the plugin/system associated with the serializer.
  • A function to clear the state.
  • A function to load the state.
  • A priority, which is used to determine the deserialization order.

    You can base the priority of your serializer on the built-in priorities

When Blockly.serialization.workspaces.save is called, each serializer's save function will be called, and its data will be added to the final JSON output:

{
  "blocks": { ... },
  "workspaceComments": [ // Provided by workspace-comments serializer
    {
      "x": 239,
      "y": 31,
      "text": "Add 2 + 2"
    },
    // etc...
  ]
}

When Blockly.serialization.workspaces.load is called, each serializer is triggered in order of priority. Serializers with more positive priority values are triggered before serializers with less positive priority values.

When a serializer is triggered, two things happen:

  1. The provided clear function is called. This ensures that the state of your plugin/system is clean before more state is loaded. For example, the workspace-comments serializer would remove all existing comments from the workspace.
  2. The provided load function is called.

XML system

The XML system allows you to serialize your workspace to an XML node. This was the original serialization system of Blockly. It has now been iceboxed, which means it will not receive new features. As such, we recommend using the JSON system if possible.

APIs

For information about the XML system's APIs please see the reference documentation.

Block hooks

For information about how to add extra serialization to blocks, see the Extensions and Mutators documentation.

Field hooks

For information about how to serialize fields, see the Custom fields documentation.

Choosing between JSON and XML

We recommend the JSON serializer over XML. The JSON system allows you to serialize the state of your workspace to a JavaScript object. This is advantageous because:

  1. JSON is easy to compress or convert to another format.
  2. JSON is easy to work with programmatically.
  3. JSON is easy to extend and append data to.

In addition, the XML system will no longer receive updates, and it already lacks features compared to the JSON serializer. For example, you can register your own JSON serializer to easily save and load additional data, such as data for plugins or customizations you've added. This is not possible in the XML system.

If you have previously used XML serialization, see the migration guide for information on how to upgrade.