ox_inventory stashes: RegisterStash, openInventory and job stashes

How to create stashes in ox_inventory: register one on the server, open it from the client or ox_target, make it personal per player, or lock it to a job.

You need a place to store things: a police evidence locker, a personal wardrobe, a safe in a house. With ox_inventory this is a stash: a named inventory with its own slots and weight limit, stored in the database. This article covers registering a stash on the server, opening it from the client, making it personal, restricting it to a job, and attaching it to an ox_target zone.

Register the stash on the server

A stash must exist on the server before anyone opens it. Register it once, when your resource starts:

lua
-- server.lua
exports.ox_inventory:RegisterStash('police_evidence', 'Evidence locker', 100, 500000, false)

The arguments, in order:

Argument Meaning
id Unique string. Used to open the stash and as its key in the database
label Name shown at the top of the stash
slots Number of slots
maxWeight Weight limit, in grams (500000 is 500 kg)
owner false for a shared stash, true for one per player, or a fixed identifier
groups Optional table of jobs allowed to open it
coords Optional position the player must be near

Only the first four are required. The contents are saved by ox_inventory, so they survive restarts of your script and of the server.

Warning: the id is the identity of the stash. If you change 'police_evidence' to another string later, the old contents stay in the database under the old id and the new stash starts empty.

Open it from the client

On the client, open the stash with the export and the same id:

lua
-- client.lua
exports.ox_inventory:openInventory('stash', 'police_evidence')

The server checks groups and coords when the request arrives, so the client cannot skip them. If the stash id was never registered, nothing opens.

You can also open a stash for a player from the server, for example from a command or an event you already validated:

lua
exports.ox_inventory:forceOpenInventory(source, 'stash', 'police_evidence')

Personal stashes: owner = true

For a wardrobe or a locker where every player has their own content, use owner = true:

lua
exports.ox_inventory:RegisterStash('personal_locker', 'Personal locker', 50, 100000, true)

The stash id is the same for everybody, but ox_inventory attaches the player identifier to it, so each player gets a separate inventory. On ESX that is the license or identifier of the character, on QBox and QBCore the citizen id.

You can also pass a fixed owner, which is useful for a house where only the owner and people you decide on may see it:

lua
local identifier = 'char1:abc123'
exports.ox_inventory:RegisterStash('house_' .. identifier, 'House storage', 80, 200000, identifier)

When the owner is a string, anyone opening that stash is attached to that owner, so the access check should happen in your own server code before you open it.

Job stashes: groups

groups is a table of job names, each with the minimum grade:

lua
exports.ox_inventory:RegisterStash(
    'police_armory',
    'Police armory',
    80,
    300000,
    false,
    { police = 0, sheriff = 2 }
)

A player with the police job at grade 0 or higher can open it, and a sheriff only from grade 2. Everyone else is refused by the server. This works with ESX jobs, QBCore jobs and QBox jobs, because ox_inventory reads them from the framework.

To also require that the player stands at the stash, pass coords as the last argument:

lua
exports.ox_inventory:RegisterStash(
    'police_armory', 'Police armory', 80, 300000, false,
    { police = 0 }, vec3(452.1, -980.2, 30.7)
)

Open it with ox_target

A stash is usually opened from a spot in the world. With ox_target, add a zone that calls the export:

lua
exports.ox_target:addSphereZone({
    coords = vec3(452.1, -980.2, 30.7),
    radius = 1.0,
    options = {
        {
            name = 'open_police_armory',
            icon = 'fa-solid fa-box-archive',
            label = 'Open armory',
            groups = { police = 0 },
            onSelect = function()
                exports.ox_inventory:openInventory('stash', 'police_armory')
            end,
        },
    },
})

The groups here only hides the option, which is a convenience. The real check is the one on RegisterStash. For zones in general, see adding an ox_target zone.

Stashes defined in a file

If you do not want to write code, ox_inventory reads stashes from data/stashes.lua. Each entry has a name, a label, slots, weight, optional owner, groups, and a location. Look at the example entries in that file on your version, copy one, and restart ox_inventory. Use code registration when a stash is created by another resource, such as a housing script.

Tip: to check whether a stash works, open it, put an item in, restart your resource, and open it again. If the item is still there, the id matches and the contents are saved.

Checklist

Symptom Fix
Stash does not open Register it on the server first, with the exact same id
Stash is empty after you rename it The id changed; the old contents are under the old id
Everyone shares the same personal stash Register with owner = true
A player without the job opens it Add groups = { jobname = grade } in RegisterStash
Opens from anywhere Pass coords as the last argument
Need items to add See adding items to ox_inventory

Quick answers

What is the difference between a stash and a player inventory in ox_inventory?

A stash is a separate storage with its own slots and weight limit, identified by a string id. It belongs to the world, a job or a single player depending on the owner and groups you give it.

How do I make a stash that is private to each player?

Register it with owner set to true. ox_inventory then keeps one separate copy of the stash per player, so two players opening the same stash id see different contents.

Why does my stash open empty or not open at all?

The stash was not registered on the server, the id differs between the register call and the open call, or the player is missing the required job or is too far from coords.

Scripts that skip this problem

Item Creator V2Create usable items with animations, props, effects and more — without writing code.View script →Shop CreatorBuild a shop in under a minute — owners, employees, vaults and robberies included.View script →

Keep reading