Quick answer: DataTables are loaded per-machine and do not replicate row edits. For runtime-modified data, copy rows into a replicated struct array on GameState and modify there. DataTables remain for static design data.

Here is how to fix Unreal multiplayer where the server modifies a DataTable row but clients still see the original. DataTables are not replicated; they are local content. For dynamic data, use replicated GameState structs.

The Symptom

Server changes a row in a DataTable at runtime. Server sees the new value. Clients still see the original from their loaded copy.

What Causes This

DataTable is content. Each machine loads its own copy from the cooked package; no replication.

Server-only modification. Modifying server’s in-memory rows does nothing for client copies.

No replication path. Unreal has no built-in mechanism to sync DataTable changes.

The Fix

Step 1: Move dynamic data to a replicated struct.

USTRUCT(BlueprintType)
struct FRuntimeItemData
{
    GENERATED_BODY()

    UPROPERTY()
    FName ItemId;

    UPROPERTY()
    int32 CurrentStock;

    UPROPERTY()
    int32 CurrentPrice;
};

// On AGameStateBase subclass
UPROPERTY(ReplicatedUsing = OnRep_Items)
TArray<FRuntimeItemData> ItemStocks;

UFUNCTION()
void OnRep_Items() { RefreshShopUI(); }

Step 2: Populate from DataTable on server start.

void AMyGameState::BeginPlay()
{
    Super::BeginPlay();
    if (HasAuthority())
    {
        for (FName row : ItemDataTable->GetRowNames())
        {
            FItemRow* r = ItemDataTable->FindRow<FItemRow>(row, TEXT("init"));
            ItemStocks.Add({ row, r->Stock, r->Price });
        }
    }
}

Authority initializes from DataTable; replication carries to clients.

Step 3: Mutate via server RPCs.

UFUNCTION(Server, Reliable)
void Server_BuyItem(FName itemId);

void AMyGameState::Server_BuyItem_Implementation(FName itemId)
{
    for (FRuntimeItemData& d : ItemStocks)
    {
        if (d.ItemId == itemId && d.CurrentStock > 0)
        {
            d.CurrentStock--;
            // Replication picks up the change
            break;
        }
    }
}

Step 4: Subscribe to OnRep on clients. OnRep_Items runs whenever the array replicates; refresh UI from there.

Step 5: Keep DataTable for static-only fields. Item display name, description, icon path stay in the DataTable (loaded the same everywhere). Stock and price live in the replicated struct.

“DataTable for static. Replicated struct for dynamic. Server mutates, clients receive via OnRep.”

Related Issues

For DataTable CSV import, see DataTable CSV. For multicast RPC, see Multicast RPC.

Replicate dynamic data via struct array. Server mutates. Clients OnRep. DataTable stays static.