Process

Scriptable Objects for Game Config Without the Mess

ScriptableObjects are the cleanest way to store game config in Unity, until they are not. Here is how to organise them so balance data stays editable and version control stays sane.

Vectra Play 6 min read
A Unity inspector showing a clean ScriptableObject with game balance values

ScriptableObjects are the right tool for game configuration in Unity when you follow three rules: one asset per concern, no runtime mutation, and a flat structure that version control can merge. Break any of the three and the system that felt clean at ten assets becomes unmanageable at a hundred.

Why ScriptableObjects for config

The alternatives are worse in specific, predictable ways.

Hardcoded constants cannot be changed without a code change and a build. Designers cannot touch them.

JSON or CSV files work but lack editor integration. No inspector, no validation, no drag-and-drop references to other assets.

MonoBehaviour fields on prefabs mix configuration with behaviour, and changing a value means checking out a prefab, which causes merge conflicts in teams.

ScriptableObjects sit in the project as assets. The inspector is the editor. Version control tracks them as YAML. Designers can change values without opening a code file.

The goal is a config layer where a designer can change any number, test it immediately, and commit the change without touching code.

One asset per concern

The first rule, and the one most projects violate.

A single "GameConfig" ScriptableObject with every value in the game is easy to create and impossible to maintain. Two people editing the same asset at the same time produces merge conflicts, and a designer looking for one value scrolls past hundreds.

Split by concern.

Each is a small asset that one person edits at a time. Merge conflicts become rare because two designers are rarely changing the same concern on the same day.

Name them consistently. A folder called Config with assets named Config_Player, Config_Economy is searchable and scannable.

No runtime mutation

The second rule, and the one that causes the strangest bugs.

ScriptableObjects in the editor persist changes made at runtime. In a build, they do not. This means a system that modifies a ScriptableObject field during play works perfectly in the editor and breaks silently in production.

The fix is simple: treat config assets as read-only at runtime. Never write to them. If gameplay needs to modify a value, copy it into a runtime data structure at load time and modify the copy.

This pattern also makes reset trivial. Restarting a level means reloading the original values from the asset, which has not changed.

Three enforcement methods, from light to strict.

  1. Convention. Agree that config assets are read-only. Works for small teams.
  2. Interface. Expose config through a read-only interface so calling code cannot access setters.
  3. Runtime copy. Load config into a plain class at startup. The ScriptableObject is never referenced during play.

The third method also improves testability, because you can construct the plain class with test values without needing an asset.

Flat structure for version control

ScriptableObjects serialize as YAML in Unity. Simple fields, arrays of primitives, and references to other assets merge cleanly. Nested structures, polymorphic lists, and serialized dictionaries do not.

Keep the structure flat.

StructureMerges wellMerges badly
Float, int, string fieldsYes
Arrays of primitivesUsually
References to other assetsYes
Nested serializable classesSometimesWhen deep
Lists of polymorphic typesYes
Serialized dictionariesYes

If you need a dictionary, consider an array of key-value structs instead. It serializes as a YAML sequence, which merges line by line rather than as a blob.

If you need polymorphic config, split it into separate ScriptableObject types with a shared base class. Each variant is its own asset, and the parent references them. This replaces one asset with complex internals with several simple assets that merge independently.

Editor tooling worth building

Two tools pay for themselves quickly.

A validation pass. A menu item that loads every config asset and checks for invalid values: negative health, prices of zero, missing references. Run it before every commit. The check is a loop over all assets of a type, which Unity makes easy with AssetDatabase queries.

A quick-access window. A custom editor window that lists every config asset as a clickable button. Faster than navigating folders, especially for a designer who changes values dozens of times a day.

Both are under fifty lines of editor code. Neither is essential at the start, but both become essential once the project has more than twenty config assets.

Config references at runtime

How gameplay code accesses config values matters as much as how they are stored.

Three approaches, ordered by complexity.

Direct reference. A MonoBehaviour holds a serialized field pointing to the config asset. Simple, explicit, and easy to trace. Best for components that always need the same config.

Service locator. A static class holds references loaded at startup. Any system can access any config. Less explicit, more flexible. Best when many systems share the same config.

Dependency injection. Config is injected into systems at construction. The most testable and the most setup. Worth it for large projects, overhead for small ones.

For a mobile game with under fifty config assets, direct references cover most needs and service locator covers the rest. Start simple and migrate if complexity demands it.

Common traps

Five mistakes that recur across projects.

What we would do

Split config by concern on day one. It takes five minutes longer than a single asset and prevents weeks of merge conflict pain later.

Enforce read-only access through a runtime copy pattern. The copy adds a small amount of code and eliminates an entire class of editor-versus-build bugs.

Build the validation pass as soon as you have ten config assets. The first bug it catches pays for the hour it took to write.

The short version

Split your current config asset this week. If you want a clean config architecture built into your project, talk to us.

Related reading: Unity Packages Worth Importing, Unity Save System Guide, and Free Tools for Solo Devs.

#Unity#Process#Tools#Design
Your turn

Got a game idea? We build it.

You bring the concept. We design, build, test and launch it, and you own 100% of the finished game.

Share Your Game Idea  →