# Add Items (/docs/guides/add-items)

To add an item in ESX Legacy, insert a row into the `items` table and reload items with `/refreshitems` (or restart the server). To make the item do something when a player uses it, register a server-side handler with `ESX.RegisterUsableItem`. If your server runs ox_inventory, items are defined in ox_inventory's own `data/items.lua` instead and the ESX `items` table is not used.

## Overview [#overview]

| What | Where |
| --- | --- |
| Item definitions (default inventory) | `items` table |
| In-memory cache | `ESX.Items`, filled by `ESX.RefreshItems()` at startup |
| Reload without restart | `/refreshitems` command |
| Add items from a script | `ESX.AddItems(items)` |
| Use action | `ESX.RegisterUsableItem(name, cb)` (server) |
| Give an item | `/giveitem` command or `xPlayer.addInventoryItem()` |

<Callout type="warn" title="Using ox_inventory?">
When the `ox_inventory` resource exists on the server, es_extended switches to ox mode automatically (`Config.CustomInventory = 'ox'`). In that mode ESX does not read the `items` table, `ESX.RefreshItems` and `ESX.AddItems` are not defined, and the ESX `/giveitem` and `/refreshitems` commands are not registered. Follow the [ox_inventory guide](/docs/guides/ox-inventory) instead.
</Callout>

## The items table [#the-items-table]

| Column | Type | Default | Description |
| --- | --- | --- | --- |
| `name` | `varchar(50)` | | Internal item name, primary key. Lowercase, no spaces, for example `water`. |
| `label` | `varchar(50)` | | Display name shown in the inventory. |
| `weight` | `int` | `1` | Weight per piece. The player's limit is `Config.MaxWeight` (24 by default). |
| `rare` | `tinyint` | `0` | Stored and passed to the inventory as `rare`. es_extended itself does not change behavior based on it; UI or third-party scripts may. |
| `can_remove` | `tinyint` | `1` | `0` blocks dropping and giving the item through the default ESX inventory. |

## Add an item with SQL [#add-an-item-with-sql]

<Steps>
<Step>
### Insert the item [#insert-the-item]

```sql title="items.sql"
INSERT INTO `items` (`name`, `label`, `weight`, `rare`, `can_remove`) VALUES
  ('energy_drink', 'Energy Drink', 1, 0, 1),
  ('lockpick',     'Lockpick',     1, 0, 1),
  ('id_card',      'ID Card',      0, 0, 0);
```

Use `INSERT IGNORE` if the script might be installed twice; `name` is the primary key, so duplicates fail otherwise.
</Step>
<Step>
### Reload items [#reload-items]

In the server console or in game as an admin:

```bash
refreshitems
```

`/refreshitems` calls `ESX.RefreshItems()`, which reloads the table and also cleans every online player's inventory: items that no longer exist are removed and the inventory is resent to the client.
</Step>
<Step>
### Give the item to test it [#give-the-item-to-test-it]

```bash
giveitem 1 energy_drink 5
```

The arguments are `[playerId] [item] [count]`; `me` works as player ID in game. The command validates that the item exists in `ESX.Items`.
</Step>
</Steps>

## Add items from a script with ESX.AddItems [#add-items-from-a-script-with-esxadditems]

If your resource needs its own items, register them at runtime so server owners do not have to run SQL.

```lua
ESX.AddItems(items)
```

| Name | Type | Description |
| --- | --- | --- |
| `items` | `table` | List of `{ name, label, weight?, rare?, canRemove? }`. `weight` defaults to `1`, `rare` to `false`, `canRemove` to `true`. |

It skips items that already exist in `ESX.Items`, validates every field (invalid entries are skipped with a console message), inserts the rest with `INSERT IGNORE` and refreshes online inventories. There is no return value.

```lua title="server/items.lua"
ESX = exports['es_extended']:getSharedObject()

if ESX.AddItems then -- not defined when ox_inventory is used
    ESX.AddItems({
        { name = 'energy_drink', label = 'Energy Drink', weight = 1 },
        { name = 'id_card', label = 'ID Card', weight = 0, canRemove = false },
    })
end
```

## Make an item usable [#make-an-item-usable]

Usable items are server-side. When a player uses the item in the default inventory, the client sends `esx:useItem`; ESX checks that the player actually has at least one, then calls your handler. ESX does **not** remove the item for you.

```lua
ESX.RegisterUsableItem(item, cb)
```

| Name | Type | Description |
| --- | --- | --- |
| `item` | `string` | Item name from the `items` table. |
| `cb` | `function(source, item, ...)` | Called with the player's server ID and the item name. |

```lua title="server/items.lua"
ESX = exports['es_extended']:getSharedObject()

ESX.RegisterUsableItem('energy_drink', function(source, item)
    local xPlayer = ESX.GetPlayerFromId(source)
    if not xPlayer then return end

    -- Remove first so a fast double-use cannot consume one item twice
    xPlayer.removeInventoryItem(item, 1)
    xPlayer.showNotification('You feel energized!')
    TriggerClientEvent('energy:boost', source, 30000)
end)
```

```lua title="client/main.lua"
RegisterNetEvent('energy:boost', function(durationMs)
    local playerId = PlayerId()
    SetRunSprintMultiplierForPlayer(playerId, 1.2)
    Wait(durationMs)
    SetRunSprintMultiplierForPlayer(playerId, 1.0)
end)
```

The handler is wrapped in `pcall`, so an error in your code prints a warning instead of breaking ESX. Registering an item marks it as `usable = true` in online players' inventories immediately. `ESX.GetUsableItems()` returns a table of all registered usable item names, and `ESX.UseItem(source, item)` lets you trigger the handler yourself.

Official addons follow the same pattern, for example `esx_basicneeds` (bread, water) and `esx_ambulancejob` (`bandage`, `medikit`).

## Work with items in scripts [#work-with-items-in-scripts]

The most used [xPlayer](/docs/es_extended/server/xplayer) inventory methods:

```lua title="server/shop.lua"
local xPlayer = ESX.GetPlayerFromId(source)

local item = xPlayer.getInventoryItem('lockpick')   -- { name, label, count, weight, usable, rare, canRemove }
if item and item.count >= 1 then
    xPlayer.removeInventoryItem('lockpick', 1)
end

if xPlayer.canCarryItem('energy_drink', 3) then
    xPlayer.addInventoryItem('energy_drink', 3)
else
    xPlayer.showNotification('Your pockets are full')
end
```

Use `ESX.GetItemLabel(name)` to show the label of an item, and `ESX.GetItems()` to get the full item registry.

### Starting items [#starting-items]

`Config.StartingInventoryItems` in `es_extended/shared/config/main.lua` is `false` by default. Set it to a table of `item = count` to give new characters items on creation:

```lua title="es_extended/shared/config/main.lua"
Config.StartingInventoryItems = { bread = 2, water = 2 }
```

It only applies to newly created players, not to existing ones.

## ox_inventory note [#ox_inventory-note]

ox_inventory has its own item list and its own way of handling item use:

- Define items in `ox_inventory/data/items.lua`. The ESX `items` table has no effect while ox mode is active.
- `ESX.Items` is filled from ox_inventory's item list, and `ESX.GetItemLabel` reads from `exports.ox_inventory:Items(name)`.
- `xPlayer.addInventoryItem`, `removeInventoryItem`, `getInventoryItem`, `canCarryItem` and `hasItem` still work; ESX routes them to ox_inventory.
- ox_inventory can run code on use through its item options (for example a `server.export`). Check the [ox_inventory docs](https://overextended.dev/ox_inventory) for how it handles items registered with `ESX.RegisterUsableItem`.

Details and setup order: [Using ox_inventory with ESX](/docs/guides/ox-inventory).

## Common issues [#common-issues]

<Accordions>
<Accordion title="'Item ... was used but does not exist!'">
The item is registered as usable but is not in `ESX.Items`. Add it to the `items` table and run `refreshitems`.
</Accordion>
<Accordion title="Items disappear from inventories after /refreshitems">
`ESX.RefreshItems` removes items from online players that are no longer in the table. That is expected when you rename or delete an item; update scripts that still give the old name.
</Accordion>
<Accordion title="/giveitem or /refreshitems does not exist">
ox_inventory is present on the server, so ESX runs in ox mode and does not register these commands. Use ox_inventory's own commands.
</Accordion>
<Accordion title="Players can carry almost nothing">
Item weights add up against `Config.MaxWeight` (default `24`). Lower item weights or raise the limit, or use `xPlayer.setMaxWeight(newWeight)` for individual players (for example when they wear a backpack).
</Accordion>
</Accordions>

## Related [#related]

- [xPlayer reference](/docs/es_extended/server/xplayer)
- [Using ox_inventory with ESX](/docs/guides/ox-inventory)
- [Database schema](/docs/guides/database-schema)
- [esx_inventory](/docs/core/esx_inventory)
- [esx_basicneeds](/docs/addons/esx_basicneeds)
