Saving and Loading in Unity

Programming and System Design · 5 minutes Read

A simple implementation guide to saving and loading in Unity.

This system also works with my Inventory and Equipment post, as well as many of my other mechanics.

When creating small polished gaming experiences intended to be played through in one sitting, many developers laze away from creating systems that may or may not be utilised. This includes things such as saving and loading, audio and graphics settings, to customisable text and resolution sizes. This, on paper, isn't that huge a problem with time generally being better spent elsewhere, but in truth, it impacts the accessibility and potentially pushes away numerous players that would have otherwise enjoyed the experience. In this post, I'll quickly cover how to create a short and clean saving and loading system in Unity. This works if you're planning on building for PC, Mac, and even Phones, and can be adapted to any game genre and mechanic you can think of with the right ingenuity.

Part 1: Implementation

Let's jump straight to it. In this example, I have a basic Unity project set up with some mechanics and variables. The inventory is a JSON List with my custom attributes, and the variables are simple static integers and booleans. The first step is setting up a JsonHelper which can be found anywhere online, but in this example, I adapted mine slightly to accommodate my custom Items class for when I later integrate the inventory. The JsonHelper allows Unity to access the JSON files, and convert them into a reference that can later be unpacked and read, as well as written on.

public static class JsonHelper
	public static T[] FromJson<T>(string json)
		Wrapper<T> wrapper = JsonUtility.FromJson<Wrapper<T>>(json);
		return wrapper.Items;

	public static T[] ToJson<T>(T[] array)
		Wrapper<T> wrapper = new Wrapper<T>();
		wrapper.Items = array;
		return JsonUtility.ToJson(wrapper);

	public static string ToJson<T>(T[] array, bool prettyPrint)
		Wrapper<T> wrapper = new Wrapper<T>();
		wrapper.Items = array;
		return JsonUtility.ToJson(wrapper, prettyPrint);

Now, you need to create the actual JSON files within the project and allow Unity to read them. Create a folder titled "StreamingAssets" within your Unity directory, and place your "Save.json" inside. If you are going to be writing data onto it you can leave it empty, however, if you plan on instantly accessing and reading from it, it's important to keep an eye on its formatting as any typos can cause Unity to crash. Below is a brief example of what my Item.json file may look like, with the left being an example of individual items, and the right being a list of my games variables.

"Items": [
		"Int": 0,
		"String": "Sword",
		"Bool": true
		"Float": 10.0,
		"Slug": "Image.png",
		"Sprite": {
			"instanceID": 14228
		"List": [
			"Value One",
			"Value Two",
			"Value Three"

To simply initialise these files you can access the JsonHelper, storing each file into a format Unity can read. Here I'm checking to see if the save file is not null, and then simply changing the variables manually. The item list is somewhat similar except I later call another condition and loop through the entire List and re-create them one by one. In this example I'm also using a free Asset called BetterStreamingAssets for its cleaner optimisation, allowing this one piece of script to work on all platforms.

void Awake()
	jsonData = BetterStreamingAssets.ReadAllText("Items.json");
	loadData = File.ReadAllText(Application.persistentDataPath + "/Save.json");
	jsonDatabase = JsonHelper.FromJson<Item>(jsonData);
	loadDataBase = JsonHelper.FromJson<Item>(loadData);

To save these variables onto the JSON file you have to create a Save Class, calling it once the player saves or moves into a new area, allowing these integers to get permanently written onto the JSON files. It's important to start and end the JSON files with the correct format to allow Unity to re-read them upon loading the game so make sure to test everything once you create it.

public void Save()
	save = "{\n \"Items\": [\n";

	SaveData toSave = new SaveData(GetComponent<ItemDataBase>());
	save += JsonUtility.ToJson(toSave, true);

	save += "\n]\n}";
	File.WriteAllText(Application.persistentDataPath + "/Save.json", save);

	// To be able to test it without building the application

Here, the SaveData class is simply storing these values and gets called when you pull the Save Class above. Despite this being quite optimised, rarely freezing or lagging the game unless you have hundreds of variables, remember to still call the Save Class only at certain periods of the game, and never under Update or FixedUpdate. Likewise, to clear the save you can simply create a ClearSave condition and call it either when a player overwrites a save, or upon not finding a pre-existing save file.