What is ox_inventory?
ox_inventory is a modern, high-performance inventory system for FiveM that has become the standard choice for serious roleplay servers. Built by the Overextended team, it replaces older inventory solutions with a system that is faster, more flexible, and easier to extend. It features a sleek React-based UI, built-in weapon management, crafting support, shops, stashes, and a powerful API that script developers can use to create custom item interactions. Whether you are building a new server or migrating from another inventory, understanding ox_inventory deeply will make you a better FiveM developer.
Installation and Configuration
ox_inventory requires ox_lib as a dependency and works with both ESX and QBCore frameworks, as well as standalone setups. The installation involves downloading the resource, importing the SQL schema into your database, and configuring the framework bridge. The configuration file controls everything from inventory weight limits to item decay timers.
-- Configuration snippet from ox_inventory
return {
playerslots = 50,
playerweight = 30000,
playerweaponslots = 5,
decay = true,
decayInterval = 60,
trunkslots = 50,
trunkweight = 60000,
gloveboxslots = 5,
gloveboxweight = 5000,
}
Registering Custom Items
Items in ox_inventory are defined in the data/items.lua file. Each item needs a unique name, a label, a weight, and optionally a stack size, decay rate, description, and client-side or server-side event handlers. Understanding the full item definition schema lets you create items that do exactly what your scripts need.
-- data/items.lua
return {
['water_bottle'] = {
label = 'Water Bottle',
weight = 500,
stack = true,
close = true,
description = 'A refreshing bottle of water',
client = {
image = 'water_bottle.png',
}
},
['lockpick'] = {
label = 'Lockpick',
weight = 200,
stack = true,
close = true,
degrade = 300,
description = 'Used to pick locks. Breaks after use.',
},
['driver_license'] = {
label = 'Driver License',
weight = 0,
stack = false,
consume = 0,
description = 'Issued by the DMV',
client = {
image = 'driver_license.png',
}
},
}
Using the ox_inventory Server API
The server-side exports are the most commonly used part of ox_inventory, allowing you to add items, remove items, check inventory contents, and manipulate metadata. Always use server-side API for item manipulation to prevent exploitation by cheaters.
-- Server-side: Adding items to a player
RegisterNetEvent('myresource:giveReward', function(itemName, count)
local src = source
local success = exports.ox_inventory:AddItem(src, itemName, count)
if success then
TriggerClientEvent('ox_lib:notify', src, {
title = 'Item Received',
description = count .. 'x ' .. itemName,
type = 'success'
})
else
TriggerClientEvent('ox_lib:notify', src, {
title = 'Inventory Full',
description = 'Could not add item to inventory',
type = 'error'
})
end
end)
-- Server-side: Check if player has required items
local function HasRequiredItems(src, requirements)
for _, req in ipairs(requirements) do
local count = exports.ox_inventory:GetItemCount(src, req.name)
if count < req.amount then
return false, req.name, req.amount - count
end
end
return true
end
-- Server-side: Remove multiple items in a transaction
local function ConsumeRecipeItems(src, recipe)
for _, ingredient in ipairs(recipe.ingredients) do
local removed = exports.ox_inventory:RemoveItem(
src, ingredient.name, ingredient.amount
)
if not removed then
print(('[ERROR] Failed to remove %s from player %d'):format(
ingredient.name, src
))
return false
end
end
return true
end
Working with Item Metadata
Item metadata is one of the most powerful features of ox_inventory. It allows you to attach arbitrary data to individual item instances, enabling unique serial numbers on weapons, expiration dates on food, player names on ID cards, and custom properties on any item.
-- Server: Create a driver license with metadata
RegisterNetEvent('myresource:issueLicense', function(targetId, licenseType)
local src = source
local metadata = {
type = licenseType,
issued = os.date('%Y-%m-%d'),
issuedBy = GetPlayerName(src),
holder = GetPlayerName(targetId),
expires = os.date('%Y-%m-%d', os.time() + 30 * 86400),
}
exports.ox_inventory:AddItem(targetId, 'driver_license', 1, metadata)
end)
-- Client: Reading metadata when using an item
exports('driver_license', function(data, slot)
local item = exports.ox_inventory:GetSlot(slot)
if not item or not item.metadata then return end
local meta = item.metadata
lib.notify({
title = 'Driver License',
description = ('Holder: %s\nType: %s\nExpires: %s'):format(
meta.holder or 'Unknown',
meta.type or 'Standard',
meta.expires or 'N/A'
),
type = 'inform'
})
end)
Creating Custom Shops
ox_inventory includes a built-in shop system that you can configure with custom item catalogs, pricing, job restrictions, and locations. Shops are defined in data/shops.lua and can be attached to ped vendors, blip locations, or triggered programmatically.
-- data/shops.lua
return {
['hardware_store'] = {
name = 'Hardware Store',
inventory = {
{ name = 'lockpick', price = 150, count = 10 },
{ name = 'screwdriver', price = 80, count = 20 },
{ name = 'radio', price = 250, count = 5 },
{ name = 'repairkit', price = 1000, count = 5 },
},
locations = {
vec3(45.6, -1749.3, 29.6),
vec3(2747.8, 3472.9, 55.7),
},
targets = {
ped = 's_m_y_hardware_01',
scenario = 'WORLD_HUMAN_STAND_IMPATIENT',
distance = 2.5,
},
},
}
Stash System and Custom Containers
Stashes are persistent storage containers that players can access at specific locations. ox_inventory supports personal stashes tied to a player identifier, shared stashes accessible by anyone, and job-restricted stashes for police evidence rooms and hospital storage.
-- Server: Register a custom stash for a property
local function CreatePropertyStash(propertyId, owner)
local stashId = ('property_%s'):format(propertyId)
exports.ox_inventory:RegisterStash(
stashId,
('Property #%s Storage'):format(propertyId),
100, -- slots
200000, -- max weight
owner -- owner identifier (or false for shared)
)
return stashId
end
-- Client: Open a stash when interacting with a storage point
RegisterNetEvent('myresource:openPropertyStorage', function(propertyId)
local stashId = ('property_%s'):format(propertyId)
exports.ox_inventory:openInventory('stash', stashId)
end)
Best Practices for ox_inventory Integration
- Always validate server-side. Never trust client-side inventory checks. Use server exports like
GetItemCountandRemoveItemfor all critical game logic. - Use metadata sparingly. While metadata is powerful, storing excessive data on every item increases database size and network traffic. Only store what you actually need.
- Handle full inventories gracefully. Always check the return value of
AddItemand provide clear feedback to the player when their inventory is full. - Use item degrade for realism. The degrade property creates natural item sinks that keep your economy balanced. Set appropriate decay times for perishable goods and tools.
- Leverage the built-in crafting system. Instead of building your own crafting logic, use ox_inventory crafting benches that handle checks, removal, and creation automatically.
- Keep item images consistent. Place all item images in
web/images/with matching filenames. Use 100x100 PNG files with transparent backgrounds for the cleanest look.