PlayDeck
Home / Course / Freelance FiveM Development
Track B · Lesson 3

Freelance FiveM Development

You already built working scripts in Track A. That is the hard part most people never finish. The gap now is not skill — it is knowing that server owners pay real money for exactly what you can already do, and that you do not need a portfolio of 50 resources to start. This lesson turns "I can script" into "I get paid to script."

What clients actually pay for

FiveM roleplay servers are run by people who want a specific feeling for their community — a custom drug lab, a tow-truck job, a heist that no other city has. Most of them can edit config files but cannot write or debug Lua. That is your buyer.

Rates today land roughly between $30 and $80 an hour, or fixed prices per job. A small bug fix might be $20–50. A polished custom job script (UI, server logic, framework integration) is commonly $80–250. Recurring "dev on retainer" arrangements for an active server can be a few hundred a month. You will start at the low end — that is normal and fine. The fastest way up is reliability: clients re-hire the dev who replies, ships, and does not leave the server broken at 2 a.m.

One mindset shift: you are not paid for hours of typing. You are paid for removing a problem the owner cannot solve themselves. Price the outcome, not your keystrokes.

The stack clients ask for

Listings are blunt about what they want. The modern, in-demand stack is ox-first:

If a client says "QBCore + ox_inventory," they are telling you the whole job. Do not show up with an ESX-only solution — mixing frameworks is the number-one beginner tell.

This is also where AI bites people. Ask a model to write a Qbox script and it will happily invent natives that do not exist, call exports from the wrong framework, or use deprecated callback patterns from a 2021 tutorial it trained on. It will also write client-trusting code that any modder can exploit. AI is a great drafting tool and a terrible authority. Pin one framework, verify every export and native against the official reference (link to the real docs — never assume), and test in the PlayDeck sandbox before you ever hand it to a paying client.

Where the work is

You do not need a network. The demand is public:

Watch the same channels for a week before pitching. You will quickly learn what jobs recur (job scripts, MLO interiors wiring, dispatch tweaks, inventory items) and what they pay.

Your portfolio is the proof

Clients buy evidence, not promises. Three small, working resources beat a long résumé. A clean one to show off: a server-validated "sell" interaction. It proves you understand lib.callback, ox_inventory, and — the thing that separates pros from script-kiddies — never trusting the client.

-- server.lua  (Qbox example — pin ONE framework, do not mix ESX/QBCore/Qbox)
-- Junkyard "sell scrap" handler.
-- SECURITY: the client only sends INTENT. The server is the source of truth.
-- A modder can fake any client event, so we re-check the inventory here.

local PRICE_PER_SCRAP = 12 -- payout per item; tune to your server's economy

lib.callback.register('playdeck_junkyard:sell', function(source, amount)
    -- Reject anything that is not a sane, positive, whole number.
    if type(amount) ~= 'number' or amount < 1 or amount % 1 ~= 0 then
        return false, 'invalid amount'
    end

    -- Trust the SERVER's count, never a number sent by the client.
    local owned = exports.ox_inventory:GetItemCount(source, 'scrap_metal')
    if owned < amount then
        return false, 'not enough scrap'
    end

    -- RemoveItem returns true only if the removal actually succeeded.
    if not exports.ox_inventory:RemoveItem(source, 'scrap_metal', amount) then
        return false, 'removal failed'
    end

    -- Pay out. Wire this to YOUR pinned framework's DOCUMENTED money export
    -- (check the current Qbox reference — do not trust an AI-guessed name).
    local player = exports.qbx_core:GetPlayer(source)
    player.Functions.AddMoney('cash', amount * PRICE_PER_SCRAP, 'junkyard-sale')

    return true
end)

The client side just calls lib.callback.await('playdeck_junkyard:sell', false, count) and reacts to the result. Notice what the example does not do: it never accepts a price or a payout from the client. That single habit is worth more to a client than any flashy UI.

Record a 30-second clip of each resource working in-game. That clip is your portfolio.

Getting paid without getting banned

Earning on FiveM has hard rules, and breaking them can nuke your account or your client's server. Treat these as principles, then always verify the current Cfx Platform License Agreement (PLA) before you sell anything:

These rules protect you. A client who asks you to build a pay-to-win shop is asking you to risk their server — say no, and explain why. That answer marks you as a professional.

Practice

This week: pick the simplest of your Track A scripts and harden it into one portfolio piece. Pin it to one framework, route every client request through lib.callback, move all validation server-side (no trusting client numbers), and verify each export against the official reference in the PlayDeck sandbox. Then record a 30-second clip of it working. One clean, exploit-proof resource and one clip is enough to answer your first hiring post.

Recap

Learn it by building it

PlayDeck is an original course on building GTA roleplay scripts with AI — Lua, frameworks, NUI, debugging, and a browser sandbox to test every lesson without booting the game.

Browse the course