How to Create a Custom Job in QBCore (2026 Guide)

Adding a custom job to your QBCore server comes down to one file: qb-core/shared/jobs.lua. Once you understand the table structure and how grades map to salaries, you can go from idea to working in-game job in under ten minutes. This guide walks through every field, shows a full worked example, covers whitelisted (allow-listed) jobs, and explains how to apply your changes safely.

If you are still setting up your server environment, the XGamingServer FiveM documentation hub covers installation, txAdmin configuration, and resource management from the ground up. And if you want a managed host that handles the infrastructure so you can focus on scripts, take a look at our FiveM server hosting plans.

Where Jobs Live in QBCore

All jobs are declared in a single shared Lua file that both the server and client load at startup:

resources/[qb]/qb-core/shared/jobs.lua

The file populates the QBShared.Jobs table. Every resource on your server that needs to check or assign a job reads from this shared table, so a single edit here propagates everywhere. The key for each entry is the internal job identifier — a lowercase string with no spaces — and the value is a table of properties.

Job Table Structure

Below is the complete set of top-level fields and what each one controls:

FieldTypeRequiredPurpose
labelstringYesPlayer-facing display name shown in HUD and menus
typestringNoJob category — e.g. leo, ems, mechanic — used by resources that branch on job type
defaultDutybooleanYesWhether the player is automatically clocked in on login
offDutyPaybooleanYesWhether the paycheck resource pays the player while they are off duty
gradestableYesRank definitions; each entry sets a rank name, salary, and optional boss flag

Inside grades, each entry is keyed by a string or number index starting at 0. The fields per grade are:

  • name — the rank title shown to the player (e.g. "Rookie", "Supervisor")
  • payment — the salary amount paid each paycheck cycle by the paycheck resource
  • isboss — optional boolean; set to true on the highest rank to grant management capabilities such as hiring and promoting through job-management UIs like qb-bossmenu

Step 1 — Add Your Job to jobs.lua

Open qb-core/shared/jobs.lua and scroll to the end of the QBShared.Jobs table. Add your new job before the closing brace. Here is a complete delivery driver example with four grades:

['delivery'] = {
    label        = 'Delivery Driver',
    type         = 'delivery',
    defaultDuty  = false,
    offDutyPay   = false,
    grades = {
        ['0'] = { name = 'Trainee',       payment = 50  },
        ['1'] = { name = 'Driver',        payment = 100 },
        ['2'] = { name = 'Senior Driver', payment = 150 },
        ['3'] = { name = 'Dispatcher',    payment = 200, isboss = true },
    },
},

A few rules to avoid silent failures:

  • The job key ('delivery') must be unique, lowercase, and contain no spaces or special characters.
  • Grades must start at 0. Gaps in the sequence are allowed but can confuse promotion UIs.
  • Only one grade should carry isboss = true; assigning it to multiple grades may cause unexpected behaviour in boss-menu resources.
  • Save the file with UTF-8 encoding — a BOM or Windows line endings can break Lua parsing on some hosts.

Step 2 — Restart qb-core to Apply the Change

Because jobs.lua is a shared file loaded at resource start, you must restart the qb-core resource (or the full server) for your change to take effect. Use any of these methods:

  • txAdmin console — navigate to Resources, find qb-core, and click Restart.
  • Server console — type restart qb-core and press Enter.
  • Full server restart — the safest option on a live server with players, since restarting only qb-core mid-session can desync player data in dependent resources.

After the restart, confirm the job loaded cleanly by checking the server console for Lua errors. If there are syntax mistakes in jobs.lua, QBCore will print the line number and stop loading.

Step 3 — Assign the Job to a Player

Admin command (in-game or console):

/setjob [player_id] [job_name] [grade]

-- Examples:
/setjob 1 delivery 0    -- assigns player 1 as Trainee
/setjob 2 delivery 3    -- assigns player 2 as Dispatcher (boss)

The /setjob command requires the admin permission level. If you need to assign jobs programmatically from a script, use the server-side function below.

Assigning Jobs from a Script (Server-Side)

The standard pattern is to retrieve the player object with QBCore.Functions.GetPlayer, validate it exists, then call Player.Functions.SetJob:

-- In a server-side Lua file of your resource
local QBCore = exports['qb-core']:GetCoreObject()

RegisterNetEvent('myresource:server:assignDelivery', function()
    local src    = source
    local Player = QBCore.Functions.GetPlayer(src)
    if not Player then return end

    -- SetJob(jobName, grade)
    Player.Functions.SetJob('delivery', 0)
    TriggerClientEvent('QBCore:Notify', src, 'You have been hired as a Delivery Trainee!', 'success')
end)

To read a player’s current job data server-side — for example to gate a function behind a specific job or grade — access Player.PlayerData.job:

local Player = QBCore.Functions.GetPlayer(source)
if not Player then return end

local jobName   = Player.PlayerData.job.name          -- e.g. 'delivery'
local gradeLevel = Player.PlayerData.job.grade.level  -- e.g. 2
local gradeName  = Player.PlayerData.job.grade.name   -- e.g. 'Senior Driver'
local isOnDuty  = Player.PlayerData.job.onduty        -- boolean
local isBoss    = Player.PlayerData.job.isboss        -- boolean

if jobName == 'delivery' and gradeLevel >= 2 then
    -- senior staff logic
end

Whitelisted Jobs

In current QBCore the concept of a “whitelisted job” is handled at the application level, not by a flag in jobs.lua. The core framework does not expose an isWhitelisted field; earlier references to QBCore.Functions.IsWhitelisted belong to older versions no longer maintained.

The modern approach is to create a separate allow-list resource or use your server’s ACE permissions to control who can be hired into sensitive jobs (police, EMS, etc.). Resources like qb-whitelist or custom job-application scripts check a database table or Discord role before calling Player.Functions.SetJob. The job definition itself in jobs.lua is identical whether the job is whitelisted or open — the restriction lives in the hiring script, not the shared config.

For a deeper look at restricting command access and role permissions, the QBCore admin commands guide covers ACE permission setup alongside the most useful admin commands for day-to-day server management.

How Paychecks Work

The payment value in each grade is the salary amount distributed each cycle by the paycheck resource on your server (commonly a resource such as qb-paycheck or a custom replacement). The paycheck resource runs a timed loop server-side; it iterates all connected players, reads Player.PlayerData.job.payment (which reflects the grade’s payment value), and deposits it into the player’s bank account — provided the player is on duty or offDutyPay is true for that job. If you are using a society/company-funds system, the resource will also check whether the company account can cover the salary before paying out.

The exact interval is set in the paycheck resource’s config, not in jobs.lua. Check that resource’s config file to tune pay frequency.

Troubleshooting Common Issues

  • Job not found after /setjob — the job key in jobs.lua does not match what you typed. Keys are case-sensitive. Check for a trailing comma on the previous entry if you added mid-table.
  • Lua syntax error on restart — open the console and note the line number. Common causes: missing comma after a grade entry, mismatched brackets, or a smart-quote character from copy-paste.
  • Player not receiving pay — confirm the player is on duty (/duty toggles duty status), check whether offDutyPay is false, and verify your paycheck resource is running (ensure qb-paycheck or equivalent in server.cfg).
  • isBoss menu not working — boss-management UIs like qb-bossmenu read the isboss flag. Confirm the flag is spelled isboss (all lowercase) in your grades entry, and that qb-bossmenu is ensured in server.cfg.

For fixing broken resource loading more broadly, see the FiveM resource loading errors troubleshooting guide — it covers the most common startup failures and how to read the server console output.

Frequently Asked Questions

Do I need to touch the database to add a job?

No — the job definition lives entirely in qb-core/shared/jobs.luaplayers table) when a player’s job is set, but the job definition does not require a database entry.

Can I add a job without restarting the entire server?

You can restart just the qb-core resource via the txAdmin console or by running restart qb-core in the server console — a full server restart is not mandatory. However, on a live server this will briefly disconnect players from the shared data object. If other resources cache job data at their own start, those resources may also need a restart to see the new job. The safest time to make jobs.lua edits is during a scheduled maintenance window.

What is the difference between defaultDuty and offDutyPay?

defaultDuty controls whether a player spawns into the server already clocked in for this job. Set it to true for civilian/freelance jobs that should always be active, and false for uniform jobs (police, EMS) where the player must explicitly clock in. offDutyPay is independent — it controls whether the paycheck resource sends a salary even when onduty is false. Most whitelisted jobs set both to false so that pay only flows when a player is actively working a shift.

Ready to play?

Run your own FiveM server with XGamingServer

Spin up an always-on FiveM server your friends can join in minutes — no port-forwarding, no tech headaches.

99.9%Uptime SLA
< 5 minInstant setup
24/7Human support
DDoSProtected
Instant setup Your server is live in minutes with a one-click control panel.
Mods & plugins Install mods, plugins and workshop content in a few clicks.
DDoS protected Enterprise DDoS mitigation keeps your server online 24/7.
Low-latency hardware Premium CPUs & NVMe SSDs for lag-free multiplayer.
Free backups Automatic backups so your world is never lost.
Real human support Gamers helping gamers — 24/7, no bots, no scripts.

Pick your FiveM plan & play in minutes

See all plans
Starter $8.40/mo 4 GB RAM Renews $12/mo Buy now
Rookie $17.50/mo 8 GB RAM Renews $25/mo Buy now
Pro $24.50/mo 12 GB RAM Renews $35/mo Buy now