PiTyUs.Hire me

Frameworks

Writing your first ESX Legacy script

Learn ESX Legacy scripting: importing ESX, the xPlayer object, money and bank accounts, inventory items, jobs and grades, usable items, ESX.RegisterCommand, client events like esx:playerLoaded and esx:setJob, and a complete example resource.

Updated 13 min readBy PiTyUs · FiveM developer

Overview

ESX Legacy is one of the two most widely used roleplay frameworks. Almost everything you do in an ESX script goes through one object — xPlayer on the server — and a handful of events on the client. Learn those and most ESX code becomes readable.

01Importing ESX

fxmanifest.lualua
fx_version 'cerulean'
game 'gta5'
lua54 'yes'

shared_scripts {
    '@es_extended/imports.lua',
    'config.lua',
}
client_script 'client.lua'
server_script 'server.lua'

dependency 'es_extended'

The xPlayer object

TaskCode
Get the playerlocal xPlayer = ESX.GetPlayerFromId(source)
IdentifierxPlayer.identifier
CashxPlayer.getMoney(), xPlayer.addMoney(n, reason), xPlayer.removeMoney(n, reason)
Bank / other accountsxPlayer.getAccount('bank').money, xPlayer.addAccountMoney('bank', n)
ItemsxPlayer.addInventoryItem('bread', 1), xPlayer.getInventoryItem('bread').count
Carry checkxPlayer.canCarryItem('bread', 5)
JobxPlayer.job.name, xPlayer.job.grade, xPlayer.setJob('police', 0)
NotifyxPlayer.showNotification('Saved')
All police onlineESX.GetExtendedPlayers('job', 'police')

02A complete example: selling fish

server.lualua
local PRICE = 45
local MARKET = vec3(-1845.0, -1195.0, 14.3)

RegisterNetEvent('fishmarket:sell', function()
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)
    if not xPlayer then return end

    if #(GetEntityCoords(GetPlayerPed(src)) - MARKET) > 5.0 then return end

    local count = xPlayer.getInventoryItem('fish').count
    if count < 1 then
        return xPlayer.showNotification('You have no fish')
    end

    xPlayer.removeInventoryItem('fish', count)
    xPlayer.addMoney(count * PRICE, 'fish market')
    xPlayer.showNotification(('Sold %d fish for $%d'):format(count, count * PRICE))
end)
client.lualua
local MARKET = vec3(-1845.0, -1195.0, 14.3)

lib.points.new({
    coords = MARKET,
    distance = 2.0,
    onEnter = function() lib.showTextUI('[E] Sell fish') end,
    onExit = function() lib.hideTextUI() end,
    nearby = function()
        if IsControlJustReleased(0, 38) then TriggerServerEvent('fishmarket:sell') end
    end,
})

The client only says “I want to sell”; the server checks the location, counts the fish and pays a price it defines. The client uses ox_lib points — add '@ox_lib/init.lua' to shared scripts, or use ESX.ShowHelpNotification with a distance loop instead.

Usable items

server.lualua
ESX.RegisterUsableItem('bandage', function(source)
    local xPlayer = ESX.GetPlayerFromId(source)
    xPlayer.removeInventoryItem('bandage', 1)
    TriggerClientEvent('medical:useBandage', source)
end)

The item must exist in your inventory’s item list (the items table for default ESX, or ox_inventory/data/items.lua with ox_inventory).

Commands

server.lualua
ESX.RegisterCommand('givefish', 'admin', function(xPlayer, args, showError)
    args.playerId.addInventoryItem('fish', args.count)
end, true, {
    help = 'Give fish to a player',
    validate = true,
    arguments = {
        { name = 'playerId', help = 'Player ID', type = 'player' },
        { name = 'count', help = 'Amount', type = 'number' },
    },
})

Client-side player data

client.lualua
RegisterNetEvent('esx:playerLoaded', function(xPlayer)
    ESX.PlayerData = xPlayer
    print('Loaded as', xPlayer.job.name)
end)

RegisterNetEvent('esx:setJob', function(job)
    ESX.PlayerData.job = job
end)

Client data is for display. Never let the client decide job, money or items — the server re-checks with xPlayer. The same script written for QBCore is in the QBCore tutorial.

Frequently asked questions

How do I get the ESX object in a script?

Add '@es_extended/imports.lua' to shared_scripts, or call exports.es_extended:getSharedObject().

How do I give money in ESX?

xPlayer.addMoney(amount, reason) for cash, xPlayer.addAccountMoney('bank', amount) for the bank.

How do I check a player’s job in ESX?

On the server: xPlayer.job.name and xPlayer.job.grade.

Why is xPlayer nil?

The player has not loaded a character yet, or you used a stale source after a wait. Check for nil.

Need this built, not just explained?

Ten years of FiveM work, from Lua to NUI

Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.

Related guides