Skip to Content
Report an error
Open in ChatGPTOpen in Claude

QBCore Structure and Core Object

Everything in QBCore  hangs off one shared table exported by qb-core. Learn its shape and most community scripts become readable.

Getting the core object

local QBCore = exports['qb-core']:GetCoreObject()

Call this once at the top of a client or server script. The returned table exposes QBCore.Functions, QBCore.Shared, QBCore.Commands and QBCore.Player.

Player data

Each connected player has a PlayerData table. The columns that persist are stored as JSON in the players table and decoded on login.

PlayerData = { source = 1, citizenid = 'ABC12345', license = 'license:...', name = 'John Doe', money = { cash = 500, bank = 5000, crypto = 0 }, charinfo = { firstname = 'John', lastname = 'Doe', birthdate = '1990-01-01', gender = 0, nationality = 'USA', phone = '555-0123', }, job = { name = 'police', label = 'Police', onduty = true, isboss = false, type = 'leo', grade = { name = 'Officer', level = 1, payment = 100, isboss = false }, }, gang = { name = 'none', label = 'No Gang', grade = { name = 'none', level = 0 } }, position = vector4(0.0, 0.0, 0.0, 0.0), metadata = { hunger = 100, thirst = 100, stress = 0, isdead = false, armor = 0 }, }
ℹ️

job.grade.level is a number on PlayerData, but grades are keyed by string in qb-core/shared/jobs.lua. Mixing the two up is the most common cause of “job not found” on a SetJob call.

metadata is a free-form table. Community scripts write into it liberally, which is why it is the thing most likely to differ between two QBCore servers.

Player data reference →  · Database schema → 

Common server calls

local QBCore = exports['qb-core']:GetCoreObject() -- Fetch a player local Player = QBCore.Functions.GetPlayer(source) local Player = QBCore.Functions.GetPlayerByCitizenId('ABC12345') local players = QBCore.Functions.GetQBPlayers() -- Money Player.Functions.AddMoney('cash', 100, 'paycheck') Player.Functions.RemoveMoney('bank', 50, 'atm-fee') local cash = Player.Functions.GetMoney('cash') -- Inventory Player.Functions.AddItem('water_bottle', 1) Player.Functions.RemoveItem('lockpick', 1) local item = Player.Functions.GetItemByName('phone') -- Job and metadata Player.Functions.SetJob('police', 1) Player.Functions.SetMetaData('stress', 0) Player.Save()

Always pass a reason string to AddMoney and RemoveMoney. It lands in the money logs and is the difference between a five-minute and a five-hour investigation when an economy exploit turns up.

Server functions →  · Client functions → 

Shared data

QBCore.Shared holds the server-wide definitions loaded from qb-core/shared/:

TableFileContents
QBCore.Shared.Itemsitems.luaEvery item definition
QBCore.Shared.Jobsjobs.luaJobs and their grade tables
QBCore.Shared.Gangsgangs.luaGangs and their grade tables
QBCore.Shared.Vehiclesvehicles.luaPurchasable vehicles and prices
QBCore.Shared.Weaponsweapons.luaWeapon hashes and ammo types

These are read at resource start. To change them at runtime, use the shared mutation exports rather than editing the tables directly.

Shared data →  · Shared exports → 

Key events

EventSideFires when
QBCore:Server:PlayerLoadedServerA character finishes loading
QBCore:Client:OnPlayerLoadedClientThe client is ready to play
QBCore:Server:OnPlayerUnloadServerA character logs out
QBCore:Server:PlayerDroppedServerA player disconnects
QBCore:Server:OnJobUpdateServerA player’s job changes
QBCore:Server:OnGangUpdateServerA player’s gang changes
QBCore:Server:OnPlayerUpdatedServerAny PlayerData key changes
QBCore:Client:OnPlayerUpdatedClientPlayerData is pushed to the client
⚠️

Never trust a client-triggered event that carries money, items or a job name. Fetch the player server-side with GetPlayer(source) and validate there. See FiveM events for the general rule.

Server events →  · Client events →  · Commands → 

Next steps