Under Construction
Unity••14 min•189 views••

[Serializable] And [SerializeField] How Is It Different?

Minh Khoa

Minh Khoa

Author

image.pngKhông thể tải ảnh bên ngoài> Short answer: [SerializeField] choose the field Unity needs to save. [Serializable] tell Unity this custom class or struct can be saved as data.

One is placed on the field, the other on the type. They do not replace each other.


Simplest Example: The Character's Weapon

We want to edit the starting weapon directly in the Inspector:

using System;
using UnityEngine;

[Serializable]
public class WeaponData
{
    [SerializeField] private string weaponName = "Wooden Sword";
    [SerializeField] private int damage = 10;

    public string Name => weaponName;
    public int Damage => damage;
}

public class Player : MonoBehaviour
{
    [SerializeField] private WeaponData startingWeapon = new WeaponData();
}

In this code:

[SerializeField] private WeaponData startingWeapon;
                 └─ Chọn field cần lưu

[Serializable] public class WeaponData
               └─ Cho phép Unity lưu data bên trong type này

Open the Inspector of Player, we will see Starting Weaponinside it there is Weapon Name and Damage.


[SerializeField]: I Want Unity to Save This Field

Unity automatically serializes public fields if their type is supported:

public int health = 100;

But public fields also let external code modify them directly:

player.health = -999;

Usually, you should keep the field private and only expose it to the Inspector:

[SerializeField] private int health = 100;

public int Health => health;

health is still saved in the Scene or Prefab, but other classes cannot freely modify it.

[SerializeField] means “save this field”, not “make this type serializable”.

The following example still does not work as expected:

[SerializeField] private Dictionary<string, int> inventory;

Because Dictionary is not directly supported by Unity's serializer. Adding [SerializeField] cannot change that rule.


[Serializable]This Custom Type Can Hold Saved Data

int, float, string, Vector3, GameObject and many built-in types are already known to Unity.

But WeaponData is a class we create ourselves. Unity needs [Serializable] to know that it can be embedded in data of Player:

[Serializable]
public class WeaponData
{
    public string weaponName;
    public int damage;
}

Just adding [Serializable] does not make WeaponData appear anywhere by itself. It must be used by a field that Unity also decides to serialize:

[SerializeField] private WeaponData startingWeapon;

Imagine there are two locks:

Field có được lưu?       → public hoặc [SerializeField]
Type có lưu được không?  → type Unity hỗ trợ hoặc custom type có [Serializable]

Both must be opened for the data to appear in the Inspector and be saved correctly.


When to Use Which?

SituationNeed to use
Want a private int appear in the Inspector[SerializeField]
Create a data class like WeaponData[Serializable] on the class
A private field whose type is WeaponDataNeed both
A class inheriting MonoBehaviour or ScriptableObjectNo need to add [Serializable]
Want to serialize static, const or readonlyNot allowed under the usual rule

Property is not a field either:

public int Health { get; private set; }

Do not rely on this property to save data into a Scene or Prefab. A more controllable pattern is to serialize the backing field:

[SerializeField] private int health;
public int Health => health;

As for [SerializeReference] Then What?

For simple data such as character stats, items, or weapon config, [Serializable] together with [SerializeField] is usually enough.

You should only think about [SerializeReference] when you really need:

  • A base-class field holding many different derived types.
  • Multiple fields each holding exactly one C# object instance.
  • Tree- or graph-shaped data with null and shared reference.

It solves a different problem and makes the Inspector and data migration more complicated. No need to use it just because the name sounds more “advanced”.


How to Remember

[SerializeField] → chọn FIELD cần lưu
[Serializable]   → cho phép custom TYPE được đóng gói

The key point: If a field does not appear in the Inspector, check two things: whether Unity is allowed to save that field, and whether the field's type is serializable. [SerializeField] solve the first one; [Serializable] solve the second one.