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:

lua
['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 extra type field that other scripts use to group them, and the file shows what your version supports.

Warning: a missing comma or brace in jobs.lua stops 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:

text
restart qb-core

Then, as an admin, in game or the console:

text
/setjob <player id> mechanic 1

The 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:

lua
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:

lua
Player.Functions.SetJob('mechanic', 1)

If QBCore is nil here, see attempt to index a nil value (global 'QBCore').

On the client

lua
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:

lua
local player = exports.qbx_core:GetPlayer(source)
if player then
    print(player.PlayerData.job.name)
end

Boss 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 = false means 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 →

Keep reading