---
title: Synchronized state in CloudBehaviours
product: Cloud Code
version: 3.0.0
latest_version: 3.0.0
status: This page documents version 3.0.0. The latest version is 3.0.0.
canonical: https://docs.unity.com/en-us/cloud-code/3.0.0/cloudbehaviours/synchronized-state
latest_url: https://docs.unity.com/en-us/cloud-code/3.0.0/cloudbehaviours/synchronized-state.md
last_updated: 2026-11-02
generated_at: 2026-11-04T12:25:24.391Z
locale: en-us
---

# Synchronized state in CloudBehaviours

> Declare synchronized state, read it in your game, and control when Cloud Code pushes updates.

> **Important:**
>
> This page describes an experimental feature that might change significantly before release. It's not recommended to use or rely on experimental features in production environments due to potential instability.

A public field or property on a CloudBehaviour is synchronized state. The member's value is stored in the cloud, and the client bindings keep an up-to-date copy. In a `MultiplayerSession` scope, every member of the session receives updates. Private members never reach a client, so secrets such as a card deck or a dice seed stay in the cloud. To notify players that something happened, rather than share a current value, use a push channel. For a comparison, refer to [Choose between a push channel and synchronized state](./push-channels.md#choose-between-a-push-channel-and-synchronized-state).

## Declare synchronized state

A public, non-static field synchronizes, and so does a public, non-static property with a setter. The setter can be private. The following example shows members that synchronize and members that don't:

```csharp title="Valid and invalid synchronized state"
[StateScope(Scope.MultiplayerSession)]
public class MatchState : CloudBehaviour
{
    // These members synchronize.
    public int Round;
    public List<int> Scores;
    public int TurnNumber { get; set; }
    public int Seed { get; private set; }

    // This field stays in the cloud.
    private List<string> _deck;
}
```

A `readonly` field or a property without a setter, such as a computed property, doesn't synchronize. The build reports a warning for each one. Synchronization and persistence follow different rules. For more information about persistence, refer to [Player and match persistence in CloudBehaviours](./persist-player-and-match-progress.md).

Values serialize as JSON. For how the client bindings represent types that you define, refer to [Model types crossing the client boundary](#model-types-crossing-the-client-boundary).

## Read synchronized state in your game

The generated client bindings expose each synchronized member as a property. Only the client bindings set these properties, when they apply state from the server. Don't assign them from your client bindings script. A value you assign doesn't change the server state, and the next update overwrites it.

Subscribe to the `Synchronized` event to react to updates:

```csharp title="Reacting to state updates"
protected virtual void OnEnable()
{
    EnableClient();
    Synchronized.AddListener(() => turnLabel.text = $"Round {Round}");
}
```

The client bindings raise `Synchronized` after each applied update. An update comes from an RPC return, an incoming push, or the hydration that runs when the client's scope resolves. Hydration runs automatically, so a client that connects and does nothing else still holds the current server state.

## Control synchronization manually

By default, `AutoSynchronize` is `true`. After each RPC returns, Cloud Code pushes updated synchronized state to the other clients in the scope. To batch several changes into a single push, set `AutoSynchronize` to `false` and call `SynchronizeAsync()` when you're ready:

```csharp title="Manual synchronization"
public async Task ResolveRound()
{
    AutoSynchronize = false;
    Round++;
    Scores[0] += 10;
    await SynchronizeAsync();
}
```

Cloud Code saves `AutoSynchronize` with the rest of the CloudBehaviour's state. After you set `AutoSynchronize` to `false`, it stays `false` for every later call in that scope until you set it back to `true`.

The calling client always receives the current state in the RPC return, regardless of `AutoSynchronize`.

A `Player`-scoped CloudBehaviour has no other clients to push to. State reaches that one client through RPC returns and hydration. A timer is the exception. A timer-triggered invocation has no RPC return, so Cloud Code pushes the updated state to the player. Refer to [What a timer callback pushes](./timers.md#what-a-timer-callback-pushes).

## Model types crossing the client boundary

When a synchronized field, an RPC, or an event uses a class, struct, or enum that you define in your cloud assembly, the Unity Editor generates a type with the same name in the client bindings. Your game can then work with the same data. The generated type is a data-only copy that keeps only the public fields and properties.

For example, the following inventory CloudBehaviour stores a list of items:

```csharp title="Cloud script"
public class Item
{
    public string Name;
    public int Quantity = 1;

    // This data stays on the server.
    private string _dropTable;

    // This logic stays on the server.
    public bool IsStackable() => Quantity > 1;
}

[StateScope(Scope.Player)]
public class Inventory : CloudBehaviour
{
    public List<Item> Items = new();

    public void Add(Item item) => Items.Add(item);
}
```

In your game, `Items` on the client bindings is a list of the following generated `Item` type:

```csharp title="Generated in the client bindings"
public class Item
{
    public string Name { get; set; }
    public int Quantity { get; set; }
}
```

The generated `Item` type affects your game in the following ways:

* Your game reads `Name` and `Quantity` directly, for example to display the inventory.
* `IsStackable()` doesn't exist in your game. To use the same rule on both sides, put the rule in a [shared rules library](./sharing-game-rules/shared-rules-library.md), or compute the result on the server and synchronize it.
* `_dropTable` never reaches your game.
* The generated type doesn't copy default values such as `= 1`. An `Item` that your game creates, for example to pass to `Add`, starts with `Quantity` at `0` unless you set it.

A public property that can be read but not publicly assigned causes a compile-time error. Examples include a computed property and a property with a private setter. A public `readonly` field also causes a compile-time error. To learn where to put game logic instead, refer to [Game organization in CloudBehaviours](./organize-your-game-into-behaviours.md).

Use `List<T>`, an array, or `Dictionary<TKey, TValue>` for a collection field. Don't use a custom collection type, because Cloud Code can't serialize a custom collection to JSON and deserialize it back. A custom collection type causes a compile-time error when you use it as an RPC parameter or return value, or when it derives from a .NET collection type.

To share a single value differently per player, refer to [Per-player state views in CloudBehaviours](./per-player-state-views.md).

## Additional resources

* [Get started with CloudBehaviours](./get-started.md)
* [Player and match persistence in CloudBehaviours](./persist-player-and-match-progress.md)
* [Per-player state views in CloudBehaviours](./per-player-state-views.md)
