Today, we are going to talk a bit about Scriptable Objects in Unity. This is a very powerful feature of Unity that are overlooked.
What is a Scriptable Object?
A ScriptableObject is like a shared notebook that multiple people can read from, instead of each person keeping their own copy of the same information.
In Unity, ScriptableObjects store data separately from game objects, so multiple objects can use the same data without creating duplicates. This helps reduce memory usage and keeps things organized.
Let’s imagine Scriptable Object as a restaurant menu. Instead of printing a separate menu for every table (which wastes paper and space), the restaurant keeps one central menu that all waiters refer to when taking orders.
Without ScriptableObjects: Each waiter carries a personal, handwritten copy of the menu, leading to inconsistencies and wasted effort.
With ScriptableObjects: All waiters check the same official menu, ensuring accuracy and efficiency.
Similarly, in Unity, instead of each object storing its own data, they all refer to one shared ScriptableObject—saving memory and keeping things consistent.
When to Use ScriptableObjects in Unity?
ScriptableObjects are best used when you need to store shared, persistent, and reusable data without creating unnecessary copies.
Let’s see how this works in Unity
Example: A prefab instance has data A, B, and C, using a total of 1KB of memory. If you create 5 instances, the total memory usage will be 5KB since each instance has its own copy of the data

However, if you store the data in a ScriptableObject and have all 5 instances reference it, the total memory usage remains only 1KB, since the data is shared instead of duplicated.

What can you do with a Scriptable Object?
Sharing Data Across Multiple Objects
Example: A game with different enemies that share the same stats (health, damage, speed).

- Instead of storing stats in each enemy’s MonoBehaviour, use one ScriptableObject that all enemies reference.
- Saves memory by avoiding duplicated data.
Then, all enemy prefabs can reference this one EnemyStats asset instead of having separate copies.This also means, its a lot easier to balance the game or change things later on. Change one value, it goes to every instance of enemies type.
Storing Game Configuration & Settings
Example: Player settings like sound volume, difficulty level, or UI preferences.
- Stores settings separately from scene objects.
- Allows easy modification without recompiling the game.
RPG inventory system with multiple weapons or spells.
[CreateAssetMenu(fileName = "NewWeapon", menuName = "ScriptableObjects/Weapon")]
public class Weapon : ScriptableObject {
public string weaponName;
public int attackPower;
}
- Makes it easy to add and modify weapons without changing code.
- Allows designers to tweak values without editing scripts.
- Also, when you want to add a weapon, then Right-click on the Project window and select ScriptableObjects/Weapons
Event System (Decoupling Objects)
Example: A global event system where one object triggers an event and multiple others listen to it.
[CreateAssetMenu(menuName = "ScriptableObjects/GameEvent")]
public class GameEvent : ScriptableObject {
public event Action OnEventRaised;
public void RaiseEvent() => OnEventRaised?.Invoke();
}
- Prevents direct dependencies between objects.
- Helps reduce complex interconnections between scripts.
Saving Persistent Data (Runtime Data Containers)
Example: Saving quest progress, high scores, or unlocked levels.
- Keeps data persistent without storing it inside scene objects.
- Can hold runtime data like player progress without relying on PlayerPrefs.
What Else Can ScriptableObjects Do?
1. Data Storage & Game Balancing
- Store reusable game data that multiple objects can reference.
- Reduce memory usage by avoiding duplicate data copies.
- Easily tweak values for game balancing without modifying code.
- Examples: Enemy stats, weapons data, character classes.
2. Runtime Data Containers (Temporary Data)
- Store temporary session data like high scores, collected items, or quest progress.
- Keeps data persistent across scenes without using singletons.
- Examples: Quest tracking, inventory system, player stats.
3. AI Behavior & State Machines
- Store different AI behaviors and switch between them easily.
- Use a modular system for defining enemy attack patterns or movement AI.
- Examples: Enemy AI states like idle, patrol, attack, flee; NPC dialogue states.
4. Dialogue & Localization System
- Store NPC dialogue in assets instead of hardcoding text in scripts.
- Easily swap between languages for localization.
- Examples: NPC dialogue lines, quest descriptions, language switching.
5. Audio & Sound Management
- Store and manage sound effects and music efficiently.
- Centralize all audio clips and references for better control.
- Examples: Sound effect database, background music tracks, dynamic music switching.
6. Procedural Generation & Level Design
- Store different biome settings, enemy spawn rates, and object placements.
- Generate dynamic levels using modular ScriptableObjects.
- Examples: Biome configurations, loot tables, dungeon layouts.
7. Ability & Skill Systems
- Define abilities separately so multiple characters can use them.
- Reuse the same ScriptableObject skills across different player classes.
- Examples: Fireball ability, healing spell, special attacks.
8. Crafting & Inventory Systems
- Store crafting recipes, item attributes, and inventory data.
- Easily adjust ingredients, item stats, and effects without changing code.
- Examples: Weapons and armor stats, alchemy recipes, item effects.
9. Multiplayer & Networking Data
- Store character loadouts, team configurations, and sync data for multiplayer games.
- Helps avoid sync issues by keeping reference-based data consistent.
- Examples: Player loadouts, multiplayer lobby settings, networked spawns.
But, some of this we can store in PlayerPrefs right?
You are right, you can store some of these data in PlayerPrefs as well, but it is created mainly for small, player preferences.
Here’s a comparison table to summarize the differences between ScriptableObjects and PlayerPrefs. Hopefully, this will show you when to use PlayerPrefs and when to use ScriptableObjects.
Feature | ScriptableObjects | PlayerPrefs |
---|---|---|
Purpose | Store structured, reusable game data | Store small, persistent player preferences |
Persistence | Exists as an asset, does not persist between sessions unless manually saved | Persists across sessions automatically |
Best For | Game configuration, shared data, asset storage | User settings, simple preferences |
Data Structure | Supports complex data structures (custom classes, lists, dictionaries) | Only supports key-value pairs (int, float, string) |
Performance | Efficient in memory, avoids duplication | Poor for large data, slow read/write for frequent updates |
Security | Data stored in Unity assets, can be encrypted | Stored in system registry or preference files, easy to modify/hack |
Recommended Size | Suitable for medium to large datasets | Best for small values (< 1KB) |
Alternatives | JSON, binary serialization, databases for persistence | JSON, file-based storage for large data |
For anything beyond simple preferences, avoid PlayerPrefs and use a more structured approach like ScriptableObjects, JSON, or databases.
What about JSON?
Feature | JSON | ScriptableObjects |
---|---|---|
Persistence | Saves to files and persists between sessions | Exists as an asset, does not persist unless manually saved |
Data Structure | Supports complex, nested structures | Supports Unity-native data types (ScriptableObjects, prefabs, etc.) |
Performance | Slower due to serialization/deserialization | Faster for in-memory data access |
Use Case | Dynamic runtime data, saving/loading game states | Predefined game data, reusable configurations |
Security | Can be encrypted but is typically plaintext | Stored in Unity assets, more secure within project |
Ease of Use | Requires manual serialization (JsonUtility, Newtonsoft.Json) | Directly accessible in Unity Editor |
Modifiability | Easily editable outside Unity (e.g., modding, cloud saves) | Not editable outside Unity unless exported |
Which One to Use and When?
- Use JSON for player saves, external data, and dynamic content that needs to persist between sessions.
- Use ScriptableObjects for game configuration and shared static data that doesn’t change frequently.
If needed, you can combine both: store game settings in ScriptableObjects and export/import them as JSON for persistence.
What about Databases?
Feature | Database | ScriptableObjects |
---|---|---|
Persistence | Stores data permanently across sessions | Exists as an asset, does not persist unless manually saved |
Best Use Case | Large-scale, dynamic data (e.g., player saves, online data) | Static, reusable game data (e.g., item stats, level data) |
Performance | Optimized for querying large data sets | Fast in-memory data access but not ideal for large data storage |
Data Structure | Highly structured with relationships (tables, keys) | Unity-native objects, easier to use in the editor |
Scalability | Easily handles large datasets and multiple users | Limited to single-player and static data |
Security | Can be encrypted, requires authentication for access | Secure within Unity but can be accessed if the asset is exposed |
Modifiability | Editable outside Unity (remote updates, live changes) | Requires re-exporting or rebuilding to modify outside Unity |
Which One to Use and When?
- Use a database for large-scale, dynamic data that must persist across sessions, especially in multiplayer or cloud-based applications.
- Use ScriptableObjects for static game data that doesn’t frequently change and is used within Unity.
For some projects, combining both makes sense. For example, use ScriptableObjects for predefined item stats and a database to track player progress and inventory in real-time.
Conclusion: ScriptableObjects vs JSON, Database, and PlayerPrefs
Each data storage method in Unity has its strengths and weaknesses. Choosing the right one depends on whether the data is static or dynamic, how it needs to persist, and how frequently it changes.
Feature | ScriptableObjects | JSON | Database | PlayerPrefs |
---|---|---|---|---|
Best For | Static game data, configs | Saving/loading structured data | Large-scale, dynamic data | Simple player settings |
Final Recommendations
- Use ScriptableObjects for static, reusable game data like character stats, item properties, or game configurations.
- Use JSON for saving/loading dynamic player data like progress, inventory, or quest states.
- Use a database for large-scale, persistent, and multiplayer data, especially in online or cloud-based games.
- Use PlayerPrefs only for small, simple settings like volume levels or UI preferences.
Hello! I hope you’re having a great day. Good luck 🙂
Hello! I hope you’re having a great day. Good luck 🙂