Skip to main content
This page contains ready-to-use Lua snippets for RedM.
All examples use oxmysql directly (e.g., MySQL.query.await) and common framework patterns.
In all of our scripts we ship a frameworkBridge.lua.
Use it to access player/job/money data on VORP or RSG, and see how to plug in a custom framework.
Reference: Framework bridge & custom setup.

1) Database: oxmysql (await)

We recommend using the await versions for predictable, synchronous-like flow on the server.

SELECT

-- server.lua
local charId = GetPlayerIdentifier(source) -- or Bridge.getCharacterId(source) if you use the bridge
local rows = MySQL.query.await('SELECT balance FROM bank_accounts WHERE charid = ?', { charId })

if rows and rows[1] then
    local balance = rows[1].balance or 0
    print(('Balance for %s: %s'):format(charId, balance))
else
    print(('No bank account found for %s'):format(charId))
end

UPDATE

-- server.lua
local affected = MySQL.update.await('UPDATE bank_accounts SET balance = balance + ? WHERE charid = ?', { 250, charId })
print(('Updated %d row(s)'):format(affected))

INSERT

-- server.lua
local insertedId = MySQL.insert.await('INSERT INTO items (name, owner) VALUES (?, ?)', { 'goldbar', charId })
print(('Inserted item ID: %s'):format(insertedId))
Always use ? placeholders. Never build SQL via string concatenation.

2) Conditions & Guards

Require supported framework (when not using custom)

if not Bridge or (Bridge.framework ~= 'vorp' and Bridge.framework ~= 'rsg' and Bridge.framework ~= 'custom') then
    print('Unsupported or missing frameworkBridge. Aborting.')
    return
end

Ensure player has an item

-- Prefer a synchronous check on the server
local function hasItem(src, item, amount)
    amount = amount or 1
    if Bridge and Bridge.framework == 'vorp' then
        local p = promise.new()
        exports.vorp_inventory:getItemCount(src, function(count) p:resolve(count or 0) end, item)
        local count = Citizen.Await(p)
        return count >= amount
    elseif Bridge and Bridge.framework == 'rsg' then
        local player = Bridge.RSGCore.Functions.GetPlayer(src)
        local data = player and player.Functions.GetItemByName(item)
        local count = (data and (data.count or data.amount)) or 0
        return count >= amount
    end
    return false
end

if not hasItem(source, 'lockpick', 1) then
    -- your notify here
    return
end

Check money

local function getCash(src)
    if Bridge and Bridge.framework == 'vorp' then
        return Bridge.getCharacterMoney(src) or 0
    elseif Bridge and Bridge.framework == 'rsg' then
        local ply = Bridge.RSGCore.Functions.GetPlayer(src)
        return (ply and ply.PlayerData and ply.PlayerData.money and ply.PlayerData.money.cash) or 0
    end
    return 0
end

if getCash(source) < 100 then
    -- your notify here
    return
end

3) Purchase flow (DB + items + money)

Minimal example showing a safe buy action on the server:
-- server.lua
local PRICE = 50

RegisterCommand('buyapple', function(src)
    -- 1) Check funds
    if getCash(src) < PRICE then
        TriggerClientEvent('ox_lib:notify', src, { description = 'Not enough cash', type = 'error', duration = 4000 })
        return
    end

    -- 2) Charge player (framework-specific)
    if Bridge and Bridge.framework == 'vorp' then
        Bridge.removeMoney(src, PRICE)
    elseif Bridge and Bridge.framework == 'rsg' then
        local ply = Bridge.RSGCore.Functions.GetPlayer(src)
        if ply then ply.Functions.RemoveMoney('cash', PRICE) end
    end

    -- 3) Give item (best-effort via framework)
    if Bridge then
        Bridge.giveItem(src, 'apple', 1)
    end

    -- 4) Persist in DB (optional audit)
    local charId = (Bridge and Bridge.getCharacterId(src)) or GetPlayerIdentifier(src)
    MySQL.insert.await('INSERT INTO purchases (charid, item, price) VALUES (?, ?, ?)', { charId, 'apple', PRICE })

    -- 5) Notify
    TriggerClientEvent('ox_lib:notify', src, { description = 'You bought an apple', type = 'success', duration = 4000 })
end)
Keep all money and inventory mutations on the server. Validate inputs; never trust the client.

4) Usable items (server-only registration)

-- server.lua
if Bridge and Bridge.registerUsableItem then
    Bridge.registerUsableItem('bandage', function(src, itemName)
        -- effect + feedback
        TriggerClientEvent('ox_lib:notify', src, { description = 'You used a bandage', type = 'success', duration = 3000 })
        -- add your heal logic here
    end)
end

5) Notifications (server & client)

Use a single code path where possible. For RSG we fallback to ox_lib notifications; VORP uses core notify.
-- server.lua
local function notify(src, text, kind)
    kind = kind or 'inform' -- 'success' | 'error' | 'inform'
    TriggerClientEvent('ox_lib:notify', src, { description = text, type = kind, duration = 4000 })
end
Client-side usage example:
-- client.lua
RegisterCommand('hello', function()
    lib.notify({ description = 'Hello from client', type = 'inform', duration = 3000 })
end)

6) Prompts (client)

-- client.lua
local GROUP = 'interaction_demo'

CreateThread(function()
    CreatePromptButton(GROUP, 'Open Menu', 0x760A9C6F) -- INPUT_CONTEXT_Y
    while true do
        Wait(0)
        DisplayPrompt(GROUP, 'Demo Actions')
        if IsPromptCompleted(GROUP, 0x760A9C6F) then
            print('[Prompt] Open Menu')
            -- open your UI
        end
    end
end)

-- later, to remove:
-- DeletePromptButton(GROUP, 0x760A9C6F)

7) Custom framework hook

If you use neither VORP nor RSG, plug your functions into the bridge once and keep scripts portable:
-- frameworkBridge.lua (custom)
Bridge.framework = 'custom'

function Bridge.getPlayerData(src)
    -- return a table matching { identifier, charid, name, money, job }
    return {
        identifier = 'steam:110000112345678',
        charid = 'CHAR_123',
        name = 'John Doe',
        money = 500,
        job = 'trader'
    }
end

function Bridge.giveItem(src, item, amount)
    -- call into your custom inventory here
end

function Bridge.removeMoney(src, amount)
    -- call into your custom economy here
end
Keep return shapes stable across frameworks. Your game logic should not need to change when switching frameworks.
I