How to add a job on QBCore: shared/jobs.lua, grades and /setjob
Add a custom job to QBCore or QBox: the shared/jobs.lua structure with defaultDuty, offDutyPay and grades, the /setjob command, and reading Player.PlayerData.job.
On QBCore a job is a block in one Lua file, not a database row. You add the block, restart the core, and set the job on a player. This guide shows the structure, the command, and how to read the job in code, for QBCore and QBox.
The structure
Open qb-core/shared/jobs.lua. Jobs are entries in the QBShared.Jobs table, keyed by the job name. Add yours:
['mechanic'] = {
label = 'Mechanic',
defaultDuty = true,
offDutyPay = false,
grades = {
['0'] = { name = 'Recruit', payment = 50 },
['1'] = { name = 'Mechanic', payment = 75 },
['2'] = { name = 'Boss', payment = 120, isboss = true },
},
},What each part means:
| Field | Meaning |
|---|---|
Key (mechanic) |
The job name used in code and /setjob: lowercase, no spaces |
label |
The name players see |
defaultDuty |
true if players start on duty when they get the job |
offDutyPay |
true if the job pays even when the player is off duty |
grades |
The ranks, keyed by their level |
name |
The rank's display name |
payment |
The pay of that rank at each paycheck |
isboss |
true marks the rank as a boss rank |
Two rules:
- Grade keys are strings on QBCore:
['0'],['1']. Start at'0'with no gaps. - Look at the jobs already in the file, such as
police, and copy their shape. Some jobs carry an extratypefield that other scripts use to group them, and the file shows what your version supports.
Warning: a missing comma or brace in
jobs.luastops qb-core from loading, and every script that depends on it with it.
Restart and set the job
The core reads the file at start:
restart qb-coreThen, as an admin, in game or the console:
/setjob <player id> mechanic 1The values are the player id, the job key and the grade number. If the command is refused, you lack admin permissions: see ACE permissions for admins.
Read the job in scripts
On the server:
local QBCore = exports['qb-core']:GetCoreObject()
RegisterNetEvent('my_script:doWork', function()
local src = source
local Player = QBCore.Functions.GetPlayer(src)
if not Player then return end
local job = Player.PlayerData.job
if job.name ~= 'mechanic' then
return TriggerClientEvent('QBCore:Notify', src, 'You are not a mechanic', 'error')
end
if not job.onduty then
return TriggerClientEvent('QBCore:Notify', src, 'Go on duty first', 'error')
end
-- allowed
end)Player.PlayerData.job holds name, label, onduty, isboss, payment and a grade table with the rank's name and level. For the rank number use job.grade.level.
To change the job from code:
Player.Functions.SetJob('mechanic', 1)If QBCore is nil here, see attempt to index a nil value (global 'QBCore').
On the client
local QBCore = exports['qb-core']:GetCoreObject()
local PlayerData = {}
RegisterNetEvent('QBCore:Client:OnPlayerLoaded', function()
PlayerData = QBCore.Functions.GetPlayerData()
end)
RegisterNetEvent('QBCore:Client:OnJobUpdate', function(job)
PlayerData.job = job
end)Reading GetPlayerData().job before the player has loaded gives nil, so wait for OnPlayerLoaded, and keep the job fresh with OnJobUpdate.
On QBox
QBox's core is qbx_core, and the jobs file is qbx_core/shared/jobs.lua. The structure is the same: a label, defaultDuty, offDutyPay and grades. Open the file and follow the entries already in it, since QBox's file can differ in details such as how the grade keys are written, and new versions may add fields.
Restart qbx_core after the edit. For code, the compatibility layer still answers exports['qb-core']:GetCoreObject(), and QBox's own export is:
local player = exports.qbx_core:GetPlayer(source)
if player then
print(player.PlayerData.job.name)
endBoss menu and funds
A grade with isboss = true is only the flag. The menu that lets the boss hire people and use the company account comes from your management resource, which usually has its own list of jobs to configure. If the boss menu does not open for your new job, check that resource's config for the job name.
Common problems
- Job not found by
/setjob. The core was not restarted, or the key is misspelled. - Core fails after the edit. A syntax error in
jobs.lua. Read the first red line in the console, and how to read a script error helps with the file and line. - Pay is not received.
offDutyPay = falsemeans the player must be on duty, and the paycheck interval comes from the core's config.
Checklist
| Symptom | Fix |
|---|---|
| Job not found | Add it to shared/jobs.lua and restart qb-core or qbx_core |
| Core will not start | Syntax error in jobs.lua; check commas and braces |
| Wrong rank | Grade keys are strings starting at '0' on QBCore |
| No pay off duty | Set offDutyPay = true or go on duty |
| Job is nil on the client | Wait for QBCore:Client:OnPlayerLoaded |
| No boss menu | Set isboss = true and add the job to the management resource |
Quick answers
Where are QBCore jobs defined?
In qb-core/shared/jobs.lua, as entries of QBShared.Jobs. On QBox the file is qbx_core/shared/jobs.lua.
Why is /setjob saying the job does not exist?
The core reads the file when it starts. Restart qb-core (or qbx_core) after the edit, and check that the job name and the grade number exist in the file.
What does isboss do?
It marks a grade as a boss grade. Boss menus and management scripts check that flag to decide who may hire, fire and use the job's funds.
Scripts that skip this problem
Advanced BoostingTablet-driven vehicle boosting: contracts from class D to S+, crews and a live queue.View script →
Shop CreatorBuild a shop in under a minute — owners, employees, vaults and robberies included.View script →
Pawn Shop AppA player-to-player pawn market inside lb-phone.View script →