Serialize Field in Unity

Serialize Field in Unity (how it works and when to use it)

In Unity by John FrenchUpdated 8 Comments

If you’re new to Unity, and you’ve only just started to write your own scripts then, chances are, you might be making your variables either public, or private.

Public if you want to access the variable in the Inspector, private if you don’t.

Like this:

public int publicNumber;
private int privateNumber;

Simple enough, right?

But that’s not really what the private and public keywords are for.

Technically, they’re Access Modifiers, and the main difference between them is that public variables can be accessed by other classes, while private variables can’t.

It just so happens that public variables are also serialized, meaning that they show up in the Inspector.

However, if you’ve been following along with tutorials and example projects then, chances are, you will have seen the public access modifier used to make a variable show up in the Inspector.

Sometimes, this is done out of simplicity, as the choice between public and private is a pretty easy concept to grasp when you’re learning how to use Unity.

However, you may have also noticed the Serialize Field attribute turn up in forums, tutorials and blog posts as well.

Which looks like this:

[SerializeField] int privateNumber;

So what is Serialize Field, how is it different to making a variable public, and should you be using it instead?

What is Serialize Field in Unity

Serialize Field is an attribute that forces Unity to serialize a variable in a script.

What does serializing mean?

Generally speaking, it means formatting data in a way that allows it to be reconstructed.

In this case, it means that a serialized variable will be visible in the Inspector.

Normally, Unity will only serialize certain public fields, which is why most public variables are visible in the Inspector.

And if they’re private, Unity doesn’t serialize them, so they don’t show up.

The Serialize Field attribute forces Unity to serialize a private field, meaning that other scripts can’t access it, but it will show up in the Inspector as if it’s public.

This works by adding the Serialize Field attribute ahead of the variable declaration.

Like this:

[SerializeField] private int privateNumber;

Or, because variables without access modifiers are Private by default anyway, it’s possible to just use the serialize field attribute and nothing else.

Like this:

[SerializeField] int privateNumber;

Technically, this is an instruction for the Unity editor, that’s why this method of revealing a variable to the Inspector is done using an attribute in square brackets, and not a keyword like the public or private access modifiers.

But why use the serialize field attribute at all?

Why not just make a variable public instead?

Why use Serialize Field?

The entire point of serializing a field in Unity is so that you can access it in the Inspector but keep it private.

This is because the process of serialization is, technically, separate from the process of making a variable publicly accessible to other classes, it just so happens that public variables are also serialized by Unity.

But, if you’re a beginner, you’ll be forgiven for thinking that the only way to edit a variable in the Inspector is by making it public.

And that’s fine, there’s nothing necessarily wrong with making a variable public.

It’s just better practice to use Serialize Field instead.

Why?

Generally speaking, you will want to keep the variables and functions in a particular script as private as possible and only expose the parts of the script that you want other classes to actually be able to change.

You may have heard this advice before, but how important is it, really?

Even if you’re working on your own, when you’re writing scripts, it can help to assume that you’re working with other people.

This means leaving comments, clearly naming things and, importantly, only providing public access to the variables and functions that are actually meant to be public.

This is because developing a game can get complicated fast and, especially if you’re working on your game in your free time, there’s a very good chance that you’re going to forget exactly how a particular script works.

And when that happens, trying to work with a script that lets you do anything and lets you access all of its data and variables can be extremely difficult, and will probably mean that you end up breaking something by using it in the wrong way.

Even if you’re the one who wrote the script.

Instead, to prevent this from happening, it can help to think of each script as a little machine, with a limited number of controls (the script’s public data and public functions), that are, each, clearly marked and easy to use.

That way, what you can do with a script is limited and, even if you forget how a script works behind the scenes, the few controls that you do have access to will make sense and will be easier to use. 

So when should you be using it instead of public or private variables?

When should you use Serialize Field in Unity?

Generally speaking, it’s good practice to only make variables public if they actually need to be public.

Realistically, this means making all of your variables Private by default.

Then, if you need to access a variable from the Inspector, use Serialize Field to do that.

Finally, if you need to be able to access a variable from another script and you need to see it in the Inspector, you can give it the highest level of access, by making it Public.

How to hide a public variable from the Inspector

There may be times when you need to make a variable public, but you don’t need to see it in the Inspector.

The Hide in Inspector attribute will prevent a public variable from being serialized, but will still allow other scripts to access it.

[HideInInspector]
public int hiddenNumber; 

// Even though it's public, this won't show in the Inspector!

Serialize Field forces Unity to show a variable in the Inspector that would otherwise be hidden.

But some data types still won’t show up, even if they’re serialized.

So what does and doesn’t work with Serialize Field?

Which data types can Unity show in the Inspector?

By default, Unity can serialize most basic data types, such as numbers, strings and boolean values, as well as reference types, such as game objects, component references and links to assets, such as audio clips and materials.

But, there are some data types that Unity can’t serialize, meaning that if you use Serialize Field with them, or even if they’re public, they still won’t show up in the Inspector.

What’s more, some serializable types won’t be visible if you use them in a particular way.

So what works, and what doesn’t?

Can Unity serialize a Static field? 

No, Unity can’t serialize static variables.

So, for example, it’s not possible to create a static variable that can be accessed by the entire scene and then change it in the Inspector.

And you can’t create a static class that holds global data and then view it in the Inspector either.

But, there are alternatives that can be used to create a similar kind of feature, such as using a Scriptable Object.

Scriptable objects work like script instances, except that they exist in the project, not the scene. This means that it’s possible to create a script that works like an asset and then put a serialized variable inside of that.

This would allow you to edit a variable that could be used across the entire scene, by referencing the scriptable object asset, but you’d be able to see and set the value in the Inspector.

Can Unity serialize a Property?

No, Unity can’t serialize properties.

Properties change how a variable is accessed, and they’re typically used to give another script limited access to a variable, such as letting it read, but not set, the value.

They can also be used to execute additional code when a variable is changed, such as converting a value, modifying it or raising an event to let other scripts know that it’s changed.

Like this:

private int number;
public int Number;
{
    get
    {
        Debug.Log("Number was read: " + number);
        return number;
    }
    set
    {
        number = value;
        Debug.Log("Number was set: " + number);
    }
}

However, properties are not serializable meaning that, even if they’re a common, serializable data type, like a number, they still won’t show up in the Inspector.

Properties are useful for creating variables that are semi-private, such as an auto-implemented property that has a public get with a private set.

This is useful when you’re using properties with reference types that other scripts may need to access but that you don’t want to be able to set, such as a Singleton.

However, because properties can’t be serialized, it means that, to create the reference, you’ll need to set it in code, using Get Component, instead of dragging it to the field in the Inspector like you might normally do.

Like this:

public class Player : MonoBehaviour
{
    public OtherScript otherScript { get; private set; }

    void Awake()
    {
        otherScript = GetComponent<OtherScript>();
    }
}

Can Unity serialize collections, such as Lists, Arrays and Dictionaries?

Normally, Unity can serialize collections, such as single-dimension Arrays and Lists, so long as the item data type contained within it is, itself, a serializable type.

However, Unity won’t serialize Dictionaries, or multi-dimensional arrays, such as 2D arrays or nested collections, such as an array of arrays.

But, there is a workaround.

If you want to create sets of data within data in the Inspector, it’s possible to create nested data types that are serializable.

This works by placing an array inside of a custom data type and then making an array out of that data type.

This works because custom data types, such as plain classes and structs are serializable.

But not by default.

How to show Structs and Plain Classes in the Inspector

Normally, when you create a reference variable that is a type of Object, such as an asset, a game object or a component, like a MonoBehaviour script that can be added to a game object, it can be serialized in the Inspector as a reference field.

For example, a script that contains a set of data like this is still, essentially, an object.

public class ExampleScript : MonoBehaviour
{
    public int numberOne;
    public int numberTwo;
    public int numberThree;
    public int NumberFour;
}

This is because it inherits from MonoBehaviour, meaning that, when you create a variable of that type, it’s serialized as a reference field that you can drag an object to, or select using the Circle Select button.

Which looks Like this:

A Reference variable type in Unity

Reference types typically allow you to select data that exists elsewhere, such as an object or an asset.

However, data structures, such as structs, and plain classes, are scripts that don’t inherit from MonoBehaviour, meaning that they can’t be added to game objects, and will have their contents serialized directly in the inspector instead, inside of the object-based script they’re contained in.

So, for example, if you make a plain class or a struct that contains a set of numbers, and then create a variable of that type in a script that is attached to an object, the numbers themselves will be visible in the inspector.

Like this:

Screenshot of a plain class that's been serialized in the Unity Inspector

Plain classes are serialized directly into the inspector, instead of just pointing to an instance that exists somewhere else.

But, this only works if the data structure is a serializable type, which it won’t be by default.

So how do you serialize it?

To make a custom class or struct visible in the Inspector, you’ll need to add the Serializable attribute to the class declaration.

Like this:

[System.Serializable]
public class ExampleScript
{
    public int numberOne;
    public int numberTwo;
    public int numberThree;
    public int NumberFour;
}

The Serializable attribute exists in the System namespace, meaning that, unless you’ve already added the System using directive, you’ll need to type System.Serializable when using the attribute.

Then, when you serialize the field, or make it public, allowing it to be serialized, the contents of the script will appear in the Inspector as values.

Now it’s your turn

Now I want to hear from you.

How are you using Serialize Field in Unity?

Do you put it on everything, or do you prefer to make your variables public instead?

And what have you learned about serializing fields in Unity that you know someone else would find useful?

Whatever it is, let me know by leaving a comment.

John French profile picture

by John French

Game audio professional and a keen amateur developer.

How was this content created

This article was written using first-hand research and experience, without the use of AI. For more information on how Game Dev Beginner articles are written, see my writing policy.

Get Game Development Tips, Straight to Your inbox

Get helpful tips & tricks and master game development basics the easy way, with deep-dive tutorials and guides.

My favourite time-saving Unity assets

Rewired (the best input management system)

Rewired is an input management asset that extends Unity's default input system, the Input Manager, adding much needed improvements and support for modern devices. Put simply, it's much more advanced than the default Input Manager and more reliable than Unity's new Input System. When I tested both systems, I found Rewired to be surprisingly easy to use and fully featured, so I can understand why everyone loves it.

DOTween Pro (should be built into Unity)

An asset so useful, it should already be built into Unity. Except it's not. DOTween Pro is an animation and timing tool that allows you to animate anything in Unity. You can move, fade, scale, rotate without writing Coroutines or Lerp functions.

Easy Save (there's no reason not to use it)

Easy Save makes managing game saves and file serialization extremely easy in Unity. So much so that, for the time it would take to build a save system, vs the cost of buying Easy Save, I don't recommend making your own save system since Easy Save already exists.

Comments

  1. I didn’t know there was such a thing as [HideInInspector].

    Some of my scripts were too long, and I was using SerializeField to receive audio clips, particles, or some transforms for raycasting. I’m not sure if it is correct, but if a GameObject has too many other GameObjects as children, I use SerializeFields to access components. Public variables make the Inspector window too noisy, and this information is very helpful for me. Thank you so much, John French.

  2. You can expose properties in the Inspector by using this:
    [field: SerializeField]
    You can’t modify the values but you can at least see the values.

  3. It is probably beyond the scope of the current article, but I think that a brief addition of a glossary of various modifiers would still benefit it, especially since [SerializedField] can apply to all of them I think (except “static”, as mentioned)
    I was always kinda confused what’s the exact differences and use cases between private, internal, and protected. “internal int”, it seems, functions analogous to “[HideInInspector] public int”, but I feel like it is a wrong conclusion.

    1. Author

      Great suggestion, I’ll make a note of this as a possible standalone article. Thanks!

  4. This is a great article, but one correction I would like to make is that it’s actually possible to serialize properties, or auto properties at least. You can do so by using [field:SerializeField].

Leave a Comment