ESX script generator

ESX script generator for FiveM

Write what your ESX resource should do and ScriptForge builds every file for es_extended — manifest, client, server, config and NUI — then compiles and checks the result before you download it.

From a description to a resource

Choose ESX in ScriptForge and describe the script: what the player does, where, what it costs and who may use it. The files are written in front of you and arrive as one zip with a README covering installation, dependencies and the check results. Changes go in the same chat; the resource is updated rather than started from scratch.

For larger ideas, switch on Plan. The free plan lists the files, events, config options and dependencies before anything is built, and you can edit it until it matches the server you run.

The ESX details it gets right

ESX has habits that trip up generic code. Every ESX build is given a framework profile, checked against es_extended 1.15.2 and its addons. Some of its rules:

  • Get ESX from @es_extended/imports.lua or exports['es_extended']:getSharedObject() — never the old esx:getSharedObject event.
  • Accounts are 'money', 'bank' and 'black_money'. There is no 'cash' account.
  • removeAccountMoney does not check the balance, so read xPlayer.getAccount(name).money first instead of trusting its return value.
  • Amounts and counts are whole numbers of at least 1, and canCarryItem runs before addInventoryItem, which checks no weight on its own.
  • Job checks read xPlayer.job.name and the numeric grade; an on-duty check is job.onDuty ~= false, and ESX.DoesJobExist runs before setJob.
  • Server callbacks use ESX.RegisterServerCallback and answer on every path; notifications go through xPlayer.showNotification.

Checks on every build

The Lua is compiled as Lua 5.4 with FiveM's syntax extensions understood, then scanned for the mistakes that cost servers money: a client-chosen price or quantity paid out, a purchase without a balance check, string-built SQL, a reward handler with no server-side distance or cooldown check. The manifest is compared with the files, and a NUI page with the messages and callbacks its Lua uses. A failing draft gets one correction before delivery, and the findings are written into the README.

Treat the checks as a safety net, not a promise: run a new resource on a test server first.

Example: an ESX coffee counter

The description, sent with ESX selected:

“Coffee shop counter using ox_target: players buy a coffee for $5 (cash) and receive the 'coffee' item. Show an error if they cannot afford it.”

The purchase handler from the server file it wrote:

server.lua
local ESX = exports['es_extended']:getSharedObject()

local busy = {}
local lastBuy = {}

local function nearCounter(src)
    local ped = GetPlayerPed(src)
    if not ped or ped == 0 then return false end
    local pos = GetEntityCoords(ped)
    for _, c in ipairs(Config.Counters) do
        if #(pos - c.coords) <= Config.ServerMaxDistance then
            return true
        end
    end
    return false
end

local function itemCount(xPlayer)
    local item = xPlayer.getInventoryItem(Config.Item)
    return item and item.count or 0
end

ESX.RegisterServerCallback('coffee_counter:buy', function(source, cb)
    local src = source
    local xPlayer = ESX.GetPlayerFromId(src)
    if not xPlayer then return cb({ ok = false, code = 'failed' }) end

    if busy[src] then return cb({ ok = false, code = 'cooldown' }) end
    local now = GetGameTimer()
    if lastBuy[src] and now - lastBuy[src] < Config.PurchaseCooldownMs then
        return cb({ ok = false, code = 'cooldown' })
    end
    busy[src] = true
    lastBuy[src] = now

    local code = 'failed'
    local ok = false

    repeat
        if not nearCounter(src) then code = 'too_far'; break end

        local price = Config.Price
        local cash = xPlayer.getMoney()
        if cash < price then code = 'not_enough_cash'; break end
        if not xPlayer.canCarryItem(Config.Item, 1) then code = 'cannot_carry'; break end

        -- ESX removeMoney has no documented return value: verify via balance change
        local called = pcall(function() xPlayer.removeMoney(price, 'Coffee purchase') end)
        local removed = called and xPlayer.getMoney() == cash - price
        if not removed then
            local diff = (cash - price) - xPlayer.getMoney()
            if called and diff < 0 then
                xPlayer.addMoney(-diff, 'Coffee purchase correction')
            end
            break
        end

        local before = itemCount(xPlayer)
        pcall(function() xPlayer.addInventoryItem(Config.Item, 1) end)
        if itemCount(xPlayer) ~= before + 1 then
            xPlayer.addMoney(price, 'Coffee purchase refund')
            break
        end

        ok = true
        code = 'ok'
        MySQL.insert('INSERT INTO coffee_purchases (identifier, item, price) VALUES (?, ?, ?)',
            { xPlayer.getIdentifier(), Config.Item, price })
    until true

    busy[src] = nil
    cb({ ok = ok, code = code })
end)
Real output of the Standard tier, from our benchmark run of 2026-10-03, where the same description went through the production ScriptForge pipeline. Copied as it came out, comments included. The resource also had fxmanifest.lua, config.lua, client.lua with the ox_target zone, an SQL file and a small NUI page.

The price is read from the config on the server, the player must stand at a counter, the cash is compared before anything is taken, and the coffee is only handed over when it fits — the money goes back if it does not arrive.

Frequently asked questions

Which ESX version is the code written for?

Current ESX Legacy (es_extended 1.15). Where older ESX differs — the on-duty field, for example — the generated check is written so it still works there.

Does it work with ox_inventory on ESX?

Name ox_inventory or ox_target in your description so the build is written for them. Otherwise it targets the xPlayer item functions ESX provides.

Will it create the database tables?

A script that stores data uses oxmysql with parameterised queries. The README's Database Setup section tells you which SQL to run before the first start.

Can I start from a plan instead of code?

Yes. Plan is free: you see and edit the files, events, config options and dependencies, and only the build itself uses credits.

What happens if a generation fails?

You are not charged. Credits are held when a build starts and only kept when the build is delivered; an incomplete build, or one whose Lua still won't compile after the automatic retry, gives them back.

Build your ESX script

Open ScriptForge, pick ESX and say what the resource should do.

Open ScriptForge

Not ready to start yet?

Leave your email. We only send updates if you tick the box below.

How we handle your address: Privacy Policy.