Skip to main content


Normcore provides several collections that can be used to synchronize data in real-time. These collections are designed to be atomic even with multiple clients making simultaneous changes to them, so they have restrictions you may not see in a typical C# collection.

Transactional collections

Transactional collections do not reflect a change to the collection until the server has confirmed the change. They also reject your change if another client has modified the same key before your change is received by the server. This is implemented by storing a version for the collection and for each key internally.


StringKeyDictionary works very similarly to a Dictionary<string, ModelType>. Any string key is supported, but behind the scenes, it is only used the first time a value is synchronized. From that point on, an ID is generated by the server and used for future updates to keep bandwidth usage to an absolute minimum.

Non-transactional collections

Non-transactional collections work like RealtimeModels in that, first, changes are reflected instantly, and second, the server merges changes using a last-client-wins approach. If you need to control how a merge conflict is handled, use a transactional collection instead.


The most commonly used collection is RealtimeSet. RealtimeSet is an unordered collection of RealtimeModels. Models can be added and removed at runtime by any clients, simultaneously, and without conflict.

RealtimeSet is the collection used by Realtime to represent instantiated prefabs. All prefabs are stored in a RealtimeSet of RealtimeViewModels. Realtime uses the presence of the model to signal that a prefab should exist in the scene.


RealtimeDictionary works similarly to Dictionary<uint, ModelType>. It is commonly used to represent a model that can have fields that are dynamically added or removed at runtime. For example, if you need to store the score for N players, you could create a ScoreModel and store instances of it in a RealtimeDictionary using each player's clientID as the key.


RealtimeArray is equivalent to a List<ModelType> that only supports adding elements. Because the contents are sorted by index, removing items by index is not supported: the server cannot correctly solve merge-conflicts if two clients attempt to remove an object at an index at the same time.

RealtimeArray is generally used for operations such as drawing brush strokes, where a series of models need to be added in order.

Tip: If you need a sorted collection that supports random removal, we generally recommend using either RealtimeDictionary with the key as the item index, or a RealtimeSet of models that can be sorted deterministically on all clients when the contents change.