We develop turnkey inventory systems for games — from a basic item list to complex crafting and network synchronization. In 5 years of work, we have completed over 20 projects for Unity and Unreal. Get a consultation on your task — we will assess the architecture and timelines in 1 day.
An inventory system is one of those components that at early stages seem simple ("just a list of items"), but by mid-project turn into a node that everything ties into: economy, progression, crafting, trading, saving. Redesigning the inventory architecture at the content production stage is one of the most painful activities in game dev.
Typical architectural mistakes laid in from the start
Item as MonoBehaviour on the scene. A common mistake among newcomers: ItemComponent on a GameObject, Inventory as List<ItemComponent>. This means each item in the inventory exists as a Unity object — impossible to serialize without hacks, hard to clone, cannot be transferred over the network. The correct way: an item in inventory is data, not a scene object.
Why separating ItemDefinition and ItemInstance is critical?
ItemDefinition is a ScriptableObject describing the item type: name, icon, base stats, stackable or not, max stack. ItemInstance is a structure or class with runtime data: quantity, durability, random affixes, enchantments. One ItemDefinition can generate thousands of different ItemInstances. Without this separation, it's impossible to properly implement item modifiers or their generation.
Tight coupling of UI to inventory data. If InventorySlot directly reads Item.name and updates Text.text, then any data refactoring breaks the UI. The inventory should work without UI at all — events (OnItemAdded, OnItemRemoved, OnItemChanged) are published via C# events or UnityEvent, UI subscribes to them externally.
How to build a robust architecture
Core — InventoryContainer: a class with List<ItemSlot> where ItemSlot stores ItemDefinition reference + ItemInstance data + int quantity. The container doesn't know whose it is — player's, chest's, shop's. This allows using one system for everything.
ItemDatabase — a ScriptableObject or addressable asset with Dictionary<string, ItemDefinition> by GUID. Item GUID is a string, not an int-ID: this simplifies merging in team work and doesn't break when new items are added.
Operations on inventory — container methods: TryAdd(ItemDefinition, quantity), TryRemove(ItemDefinition, quantity), TryMove(fromSlot, toContainer, toSlot). Each method returns bool or InventoryOperationResult with an error code (not enough space, item not found, slot blocked). No void methods for data operations.
Stacking and unique items
Stackable resources (wood, gold, ammo) and unique items with affixes require different addition logic. TryAdd checks itemDef.isStackable — if yes, looks for an existing slot with the same ItemDefinition and fills up to maxStackSize, remaining goes into a new slot. If !isStackable — each instance occupies a separate slot with its own ItemInstance.
Inventory sorting — an algorithm that rearranges slots by category and within a category by name. Implemented via List.Sort() with a custom IComparer<ItemSlot> and animated via coroutine with sequential swap positions — otherwise visually indistinguishable what happened.
Saving inventory state
Serialization is a separate task. ItemInstance must serialize into a JSON-friendly structure: { "defGuid": "abc123", "quantity": 5, "durability": 87, "affixes": [...] }. Unity's JsonUtility works poorly with polymorphism — for complex ItemInstance with inheritance, better to use Newtonsoft.Json (via com.unity.nuget.newtonsoft-json) with custom converters.According to the official Unity documentation, JsonUtility does not support inheritance — use third-party libraries for complex models.
On save load: deserialize the list of slots, find ItemDefinition in ItemDatabase by GUID, restore ItemInstance. If an ItemDefinition with that GUID is not found (content removed), the slot is marked as orphaned and does not cause a crash.
Case study: inventory for an MMO shooter
A project with 200+ unique items and procedural affix generation. Without Definition/Instance separation, 200 ScriptableObjects would be needed, and each item with affixes would be a separate instance. Solution: 40 Definitions, Instances generated on the fly. Save — 5 ms for 10,000 items. UI updates via events, sorting — 0.2 ms.Estimated timeline table
| Scale | Scope | Duration |
|---|---|---|
| Minimal | Item list, add/remove, UI slots | 3–7 days |
| Basic | Stacking, ItemDefinition/Instance, saving | 1–2 weeks |
| Medium | Crafting, equipment, drag & drop UI, filters | 3–5 weeks |
| Full | Affix generation, trading, network sync | 2–3 months |
Resource management: when inventory is more than items
In strategy and survival games, resources (wood, food, electricity) live not in inventory slots, but in ResourceSystem — a global or structure-bound registry with Dictionary<ResourceType, float>. Updates happen via Tick every N seconds of game time, not in Update() every frame.
Producers and consumers of resources register in ResourceSystem through the IResourceProducer / IResourceConsumer interface. This allows adding new buildings without changing the core system. Resource flow balance is checked in an editor tool even before runtime — a table with current production and consumption by type updates in a custom Editor Window via EditorApplication.update.
What is included in inventory system development
- Architecture:
ItemDefinition/ItemInstance,InventoryContainer,ResourceSystem - Implementation of operations: add, remove, move, sort, stacking
- Serialization and saving: JSON, binary option, compression
- UI: custom slots, drag & drop, filters, categories (if needed — for gamepad or mobile control)
- Optimization: object pooling, asset addressing, async loading
- Integration with crafting, trading, equipment, network sync
- Unit tests: coverage of all operations, including edge cases
- Documentation: architecture description, configuration guide, content maker manual
- Deployment and support: assistance with integration into an existing project
Work process
Design starts with a table of all item types and their properties — before writing code. How many unique items are planned? Are there generated ones? Is crafting needed? This determines the depth of architecture. A prototype InventoryContainer without UI is written first and covered with unit tests in Unity Test Runner — add, remove, overflow, save/load. UI is connected last.
Contact us to discuss your project. Get an architecture and timeline estimate within one business day.





