gta6/prompts
jobs
Freebeginnerjobs

Basic ESX Job System

Register a custom ESX job with graded ranks, salaries, and clock-in/out events — the smallest complete job resource you can ship.

NON-TESTÉ — the reference Lua is syntax-validated, not run in a live FiveM server. Adapt and test on your own dev server before shipping.
Est. Lua
~65 loc
Claude
Claude Opus 4.x / Sonnet 4.x
Validation
syntax-validated
Updated
2026-06-25

Description

A complete, minimal ESX job resource: it registers a custom job (garbage) with three graded ranks and salaries, then exposes clock-in and clock-out events so a player can take and drop the job at runtime. This is the canonical starting point for any role-based gameplay on an ESX server — police, EMS, mechanic, and delivery jobs are all variations on this skeleton.

Prompt Template

You are writing a FiveM server script for es_extended (stable, exports-based
getSharedObject). Create a single server-side Lua file that:

1. Registers a job named "[JOB_NAME]" with label "[JOB_LABEL]" and these
   grades: [GRADES — list of {grade, name, label, salary}].
2. Inserts the job into ESX.Jobs directly (do NOT call ESX.RegisterJob — it does
   not exist in stable es_extended).
3. Adds RegisterNetEvent handlers "[RESOURCE]:clockIn" (accepts a grade) and
   "[RESOURCE]:clockOut" (sets the player to unemployed), each resolving the
   xPlayer via ESX.GetPlayerFromId(source) and guarding against nil.
4. Registers the job inside onResourceStart, guarded with
   GetCurrentResourceName() so it only runs for THIS resource.

Return only the Lua. No prose, no markdown fences.

Expected Output

See content/expected-outputs/jobs/01-basic-job-system.lua. It is syntax-validated with luaparse (our build gate); it has not been run against a live FiveM server, so treat it as a verified-syntax starting point, not a drop-in guarantee.

01-basic-job-system.lua65 lines
-- 01-basic-job-system.lua
-- Server-side ESX job registration + clock-in/out for a basic "garbage" job.
-- Drop into a resource's server/ folder; requires es_extended.

local ESX = exports["es_extended"]:getSharedObject()

-- Job definition registered on resource start.
local JOB_NAME = "garbage"
local JOB_LABEL = "Garbage Collector"

local JOB_GRADES = {
    { grade = 0, name = "recruit",  label = "Recruit",  salary = 200 },
    { grade = 1, name = "driver",   label = "Driver",   salary = 350 },
    { grade = 2, name = "boss",     label = "Boss",     salary = 600 },
}

-- Register the job + its grades with ESX's in-memory job table.
local function registerJob()
    local grades = {}
    for _, g in ipairs(JOB_GRADES) do
        grades[tostring(g.grade)] = {
            job_name    = JOB_NAME,
            grade       = g.grade,
            name        = g.name,
            label       = g.label,
            salary      = g.salary,
            skin_male   = "{}",
            skin_female = "{}",
        }
    end

    ESX.Jobs[JOB_NAME] = {
        name   = JOB_NAME,
        label  = JOB_LABEL,
        grades = grades,
    }
end

-- Clock a player into the job at the given grade (defaults to recruit).
RegisterNetEvent("basic-job:clockIn", function(grade)
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)
    if not xPlayer then return end

    local targetGrade = tonumber(grade) or 0
    xPlayer.setJob(JOB_NAME, targetGrade)
    TriggerClientEvent("esx:showNotification", src, "You clocked in as " .. JOB_LABEL)
end)

-- Clock a player back out to unemployed.
RegisterNetEvent("basic-job:clockOut", function()
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)
    if not xPlayer then return end

    xPlayer.setJob("unemployed", 0)
    TriggerClientEvent("esx:showNotification", src, "You clocked out.")
end)

AddEventHandler("onResourceStart", function(resourceName)
    if GetCurrentResourceName() == resourceName then
        registerJob()
    end
end)

Known Failure Modes

  • Hallucinated ESX.RegisterJob — not a real stable-ESX function. The prompt explicitly forbids it; if Claude still emits it, insert into ESX.Jobs directly or seed the jobs / job_grades DB tables.
  • Wrong getSharedObject retrieval — exports vs. legacy TriggerEvent callback differs by ESX version. Pin the version in your prompt.
  • Unguarded onResourceStart — without the GetCurrentResourceName() check the job re-registers on every resource start.

Integration Notes

  • Place the file under your resource's server/ folder and list it as a server_script in fxmanifest.lua.
  • es_extended must start before this resource (set it as a dependency).
  • To persist the job across restarts, also insert it into the jobs and job_grades database tables — the in-memory registration here is lost on server restart.

Profit Potential

$300–$4000/mo on Tebex (expected ~$1100). [INFERRED] priced inside the $50-389 script band against the signal-scraper tebex_snapshot corpus (median seller $11.85K/mo, n=100), scaled for a hot job-systems niche at beginner difficulty — high unit volume on a low ticket.

Trend Signal

🔥 hot — custom FiveM job systems = niche-selection LAUNCH #1 (4.75).

Sales Angle

Position as the boilerplate every server owner clones on day one — graded ranks, salaries, and clock-in/out with zero bloat. Sell cheap as a funnel into your paid jobs, or list at $59 as a no-friction starter.

Difficulty & Ship Time

beginner · ships in 2-4h.