08 December 2025

Dictionary Serialization in Unity

In development, serialization consists of changing the format of an object in memory so that it can be stored on disk.

One of the most popular serialization formats is JSON, a text standard that allows you to save data in files following a key-based structure very similar to Python dictionaries.

When you serialize an object—an instance of a class—into JSON, what you do is select the key data of the object and convert them into fields and values in a JSON file. What are the key data of the object? It’s the minimum subset of data that allows you to reconstruct the object in the state you need. That reconstruction process is called deserialization and is the inverse of the other: you read the file and use its content to create an instance of the class with a state as close as possible to the original.

Unity is constantly serializing and deserializing. When we use the inspector to assign a value to a public field of a MonoBehaviour, Unity serializes that value into its own format so that you have it in the inspector the next time you start the editor. By default, Unity performs this process with all public fields of MonoBehaviours and ScriptableObjects, but you can also force it on private fields if you define them preceded by the [SerializeField] attribute. This attribute also allows us to edit private fields in the inspector. Without it, the inspector only shows public fields. Be careful—this does not mean you should use this attribute on all private fields of your MonoBehaviour. Its use only makes sense for those fields that contain base values for your class, that is, those you would configure in the inspector before the game runs. Preceding a calculated field with [SerializeField] would make no sense unless you wanted to preserve that calculated value for a later execution.

That was precisely the case that led me to write this article. I’m writing a class that allows me to analyze a scenario and generate a graph representing all its walkable areas. The graph creation process is irrelevant here, but my idea was for the graph to be generated during development, saved, and loaded at runtime. In other words, I wanted my graph to be saved in a ScriptableObject. One of the components of my graph is based on a dictionary whose keys are the integer coordinates of a rectangular grid, and whose values are nodes with links to neighboring nodes. And the problem arises because Unity does not know how to serialize dictionaries. It can serialize lists, but not dictionaries. That’s why you can edit lists in the inspector but not dictionaries.

Dictionaries are one of the most common data structures in development, so I’m not the first to encounter this problem. It’s so common that other engines, like Godot, proudly support dictionary serialization.

How can you work around this problem? Well, you can create a class that outwardly behaves like a dictionary but internally is based on two lists—one for keys and one for values. During serialization, those two lists would be saved since Unity can process lists. During deserialization, those two lists would be read and used to create an internal dictionary in memory from which the class would offer its functionality to the rest of the game components. This solution is perfectly legitimate, but by now it’s so widely used that it has already been included in a multi-type serialization tool (not just dictionaries) called Odin Serializer. So it would be like reinventing the wheel. If, despite that, you want to do it yourself, Odin’s own page explains how, although it warns that the devil is in the details and that there can be odd situations when editing prefabs that may require significantly refining the initial implementation. That path has already been traveled by the Odin Serializer team, so I’ll explain how to use it.

Odin Serializer Logo
Odin Serializer Logo

Odin Serializer is an open-source and free tool. You can download it from its website as a Unity package containing all the source code files to serialize everything Odin supports. Odin Serializer is just the free entry point to a set of tools that are paid. From the free serializer, they offer a tool to create custom inspectors and another to find errors in your projects. Both are extremely powerful. The first lets you skip the UI Toolkit step when implementing convenient and efficient inspectors. The second detects the most common errors in Unity development and provides a set of custom attributes to add semantics to your fields and detect cases where their values do not match their semantics (or even prevent you from entering those values). Although for this article I only needed the free serializer, I recommend checking out their other tools and prices. They are one-time purchases and very affordable for an indie developer.

The download page only asks for your game’s base namespace to customize the namespaces of all included code files. The package includes an OdinSerializer folder containing the rest of the tool’s folders. You need to place that folder inside your game’s Scripts folder.

Once imported into your Scripts folder, OdinSerializer provides a set of specialized classes that inherit from the usual Unity ones:

  • SerializedBehaviour
  • SerializedComponent
  • SerializedMonoBehaviour
  • SerializedNetworkBehaviour
  • SerializedScriptableObject
  • SerializedStateMachineBehaviour
  • SerializedUnityObject

You just need to replace the Unity class your component inherits from with the equivalent Odin class so that Odin handles serialization for types Unity doesn’t support. All dictionaries, for example, will be serialized by Odin without any extra effort, so if you edit their content in the editor, it will persist between executions.

However, keep in mind that even if you serialize the dictionary content with Odin, Unity’s inspector will still be unable to display it. So don’t be surprised if your public dictionary still doesn’t appear in the inspector. For that, you’d need to install Odin Inspector, which is one of the paid components. Without that component, any modification of the serialized dictionary content from the editor would need to come from custom scripts executed in the editor. That was precisely my case, as I configured a button in my graph component’s inspector to generate the grid when clicked and save the values created in the component’s internal dictionary. If I modify the scenario, I just click the button again to regenerate the graph’s grid.

Odin Serializer should cover most of your needs for serializing dictionaries, but it’s not always that simple. Although I had used Odin Serializer in simpler projects, I couldn’t get it to work in the project that inspired this article. It generated my graph correctly when I clicked the button, but the graph wasn’t there on the next editor restart or level reload. For whatever reason, the dictionary containing the graph wasn’t saved when the level was stored. I’ve thought about it a lot and don’t know if it’s because I have several levels of nested dictionaries, or because the scripts containing those dictionaries are placed in nested prefabs. It could also be because my component uses a custom editor, adding another level of indirection to data serialization. Whatever the reason, I ultimately had no choice but to implement my own serialization—the very manual serialization I warned against if Odin could solve your problem. This time, I had to reinvent the wheel, though I was lucky to rely on the method explained on Odin Serializer’s own page. I’ll tell you how, in case it helps you out sometime.

As I said before, the key is to create a class that inherits from Dictionary to preserve its functionality. To give this new class the ability to be serialized in Unity, it must implement the ISerializationCallbackReceiver interface. When Unity receives the command to serialize a class—because the field of that class is public or marked with the [SerializeField] attribute—it expects that class to implement the ISerializationCallbackReceiver interface. This interface consists of two methods: OnBeforeSerialize(), where we implement how we want to save our object’s information during serialization, and OnAfterDeserialize(), where we implement how to recover the saved information to reconstruct the object’s state.

The class I created is based on two lists: one for the dictionary’s keys and another for its values. These lists will store the data to be preserved since Unity natively serializes lists.

Fields of my customizable dictionary
Fields of my customizable dictionary

Now the interface implementation. First, for the serialization process.

Serialization process of my customizable dictionary
Serialization process of my customizable dictionary

When Unity calls OnBeforeSerialize(), it’s time to save the object’s state information. To do this, I clear the previous content of the lists (lines 42 and 43) and then refill them with the updated list of keys and values from the dictionary. When the class instance closes, the dictionary’s content will be lost, but the lists will have been serialized along with the rest of the scene’s information.

Now the inverse process. The scene opens again, and Unity calls the OnAfterDeserialize() methods of all its objects so they can restore their previous state from the deserialized information.

Deserialization process of my customizable dictionary
Deserialization process of my customizable dictionary

As shown in the listing, since the lists were serialized, they will remain intact when OnAfterDeserialize() is called, allowing us to use them to restore the dictionary’s entries. In lines 34 to 36, you can see that I iterate through both lists to regenerate the entries of the class’s internal dictionary.

Now comes something important. Unity cannot serialize generic types, and the newly created class (UnitySerializedDictionary) is generic. The solution is to specialize the generic class for each use case. Once concretized, the resulting class can be serialized by Unity. That’s why I have a separate static file with the different concretized versions of the generic dictionary.

Concrete classes derived from the generic one
Specialized classes derived from the generic one

To avoid any temptation to use the generic class directly without concretizing it, it’s best to mark it as abstract.

These specialized versions are the ones we can use in our code, with the assurance that Unity will preserve their content between executions.

Using the concretized dictionary
Using the specialized dictionary


MonoBehaviour that uses our concretized and serializable dictionary
MonoBehaviour that uses our specialized and serializable dictionary

I hope you found this useful and that it helps you feel confident about using dictionaries in your components.