Skip to main content
  • Instant digital delivery
  • Lifetime updates on selected products
  • Trusted by server owners
FiveMX
Shop
Full ServersBundlesNew releases
  1. Home
  2. Blog
  3. Development
Table of Contents
Why an Adapter?How to Use (Drop‑in)Interface Contract (stable surface)FW.metaFW.PlayerFW.JobFW.MoneyFW.Inv (best‑effort; see Notes)FW.EventsDrop‑in Adapters (copy/paste)shared/fw.luashared/adapters/esx.luashared/adapters/qb.lua (QBCore)shared/adapters/qbox.lua (QBOX / qbx\_core)Usage Examples1) Paying a job bonus2) Inventory grant with ox fallback already handledAnti‑Pattern Catalog (and Fixes)SQL & Identifier Migration Notes (Quick Reference)Testing Matrix & CI: Validate a Script Across Frameworks1) Minimal test (Busted)2) GitHub Actions (luacheck + busted)Implementation ChecklistFrequently Extended Surface (optional add‑ons)Tri‑way Mapping Quick TableFinal Notes

Adapter Patterns: ESX, QBCore & QBOX (Exports, Events & APIs)

Published on August 16, 2025·by Lars Miller(Founder & Lead Editor)·Credentials·4 min read·Updated on May 14, 2026
Development

This is a FiveM Framework Adapter for scripters. Deliver a single resource that runs on ESX, QBCore, and QBOX by isolating framework-specific calls behind a lean adapter.

Share
Adapter Patterns: ESX, QBCore & QBOX (Exports, Events & APIs)
Adapter Patterns: ESX, QBCore & QBOX (Exports, Events & APIs)

This is a FiveM Framework Adapter - for scripters. Ship one resource that runs on ESX, QBCore, and QBOX by isolating framework‑specific calls behind a thin adapter. Drop the shared/fw.lua and per‑framework adapters below into any resource, call the stable interface contract (FW.Player, FW.Job, FW.Money, FW.Inv, FW.Events), and keep business logic framework‑agnostic. A small test matrix with stubs catches mismatches before you deploy.


Why an Adapter?

Framework differences cluster around the same seams:

  • Core access (ESX getSharedObject, QBCore GetCoreObject, QBOX exports only)
  • Player model (xPlayer vs Player/PlayerData)
  • Identifiers (license/steam vs citizenid)
  • Money & inventory APIs
  • Event names at load/login/job‑update time

A unified interface keeps these seams out of your game logic. You swap the adapter, not the codebase.

BTW: You can use our written adapter here, for free:

Framework Adapter


How to Use (Drop‑in)

Tree (suggested):

my-resource/
├─ fxmanifest.lua
├─ shared/
│  ├─ adapters/
│  │  ├─ esx.lua
│  │  ├─ qb.lua
│  │  └─ qbox.lua
│  └─ fw.lua
├─ server/
│  └─ main.lua
└─ client/
   └─ main.lua

fxmanifest.lua (load adapters first, then fw.lua so detection can bind):

fx_version 'cerulean'
game 'gta5'
lua54 'yes'

shared_scripts {
  'shared/adapters/*.lua',
  'shared/fw.lua'
}

client_scripts {
  'client/*.lua'
}

server_scripts {
  '@oxmysql/lib/MySQL.lua', -- optional: if you use SQL
  'server/*.lua'
}

In your code (server or client):

-- use the stable interface everywhere
local src = source
local p = FW.Player.getBySrc(src)
local job = FW.Job.getName(p)
FW.Money.add(p, 'cash', 250, 'delivery-bonus')
FW.Inv.addItem(p, 'water', 1)
FW.Events.notify(src, 'Job bonus paid.', 'success')

The only symbol you depend on is FW. Everything else is internal to the adapters.


Interface Contract (stable surface)

Design goal: Small, explicit, documented. These are the functions you can rely on across frameworks.

FW.meta

  • name() -> 'esx'|'qbcore'|'qbox'
  • has(resourceName: string) -> boolean (resource started?)

FW.Player

  • getBySrc(src: number) -> any (framework player handle)
  • getStateId(p) -> string (ESX: identifier; QB/QBOX: citizenid)
  • getServerId(p) -> number (numeric id)
  • getName(p) -> string

FW.Job

  • getName(p) -> string
  • getGrade(p) -> number|string
  • onChange(handler(src, oldJob, newJob)) (fires when job changes, if detectable)

FW.Money

  • get(p, account: 'cash'|'bank'|'black_money'?) -> number
  • add(p, account, amount: number, reason?: string)
  • remove(p, account, amount: number, reason?: string)

FW.Inv (best‑effort; see Notes)

  • addItem(p, name: string, count: number, metadata?: table) -> boolean
  • removeItem(p, name: string, count: number, metadata?: table) -> boolean

Inventory note: servers vary (qb-inventory, ox_inventory, qs‑inventory, etc.). The default implementation uses framework inventory when available and falls back to ox_inventory if detected.

FW.Events

  • notify(target: number, msg: string, type?: 'info'|'success'|'error')
  • onPlayerLoaded(handler(src)) (best‑effort, with fallback via playerJoining)

Drop‑in Adapters (copy/paste)

These are pragmatic defaults. If your fork differs (especially for QBOX), adjust the few marked comments.

shared/fw.lua

-- framework bridge bootstrap
FW = FW or {}

local function started(name)
  local st = GetResourceState(name)
  return st == 'started' or st == 'starting'
end

local which
if started('qbx_core') then which = 'qbox'
elseif started('qb-core') then which = 'qbcore'
elseif started('es_extended') then which = 'esx' end

if which == 'qbcore' then
  FW = Adapters.qb()
elseif which == 'qbox' then
  FW = Adapters.qbox()
elseif which == 'esx' then
  FW = Adapters.esx()
else
  error(' No supported framework found (es_extended / qb-core / qbx_core).')
end

-- tiny helpers common to all adapters
function FW.meta.has(res)
  return started(res)
end

shared/adapters/esx.lua

Adapters = Adapters or {}

Adapters.esx = function()
  local ESX = exports['es_extended']:getSharedObject()

  local M = {
    meta = { name = function() return 'esx' end },
    Player = {}, Job = {}, Money = {}, Inv = {}, Events = {}
  }

  -- Player
  function M.Player.getBySrc(src) return ESX.GetPlayerFromId(src) end
  function M.Player.getStateId(p) return p.identifier end
  function M.Player.getServerId(p) return p.source end
  function M.Player.getName(p) return p.getName and p.getName() or GetPlayerName(p.source) end

  -- Job
  function M.Job.getName(p) return (p.getJob and p.getJob().name) or (p.job and p.job.name) end
  function M.Job.getGrade(p)
    local j = p.getJob and p.getJob() or p.job
    return j and (j.grade or (j.grade and j.grade.grade))
  end
  function M.Job.onChange(handler)
    -- ESX fires when job changes (commonly 'esx:setJob')
    RegisterNetEvent('esx:setJob', function(job)
      local src = source
      handler(src, nil, job and job.name)
    end)
  end

  -- Money
  local function norm(account) return account == 'cash' and 'money' or account end
  function M.Money.get(p, account)
    account = norm(account)
    if account == 'money' then return p.getMoney() end
    local acc = p.getAccount and p.getAccount(account)
    return acc and acc.money or 0
  end
  function M.Money.add(p, account, amount)
    account = norm(account)
    if account == 'money' then p.addMoney(amount) else p.addAccountMoney(account, amount) end
  end
  function M.Money.remove(p, account, amount)
    account = norm(account)
    if account == 'money' then p.removeMoney(amount) else p.removeAccountMoney(account, amount) end
  end

  -- Inventory (ESX native, with ox fallback)
  local hasOX = GetResourceState('ox_inventory') == 'started'
  if hasOX then
    function M.Inv.addItem(p, name, count, meta) return exports.ox_inventory:AddItem(p.source, name, count, meta) end
    function M.Inv.removeItem(p, name, count, meta) return exports.ox_inventory:RemoveItem(p.source, name, count, meta) end
  else
    function M.Inv.addItem(p, name, count) p.addInventoryItem(name, count); return true end
    function M.Inv.removeItem(p, name, count) p.removeInventoryItem(name, count); return true end
  end

  -- Events
  function M.Events.notify(target, msg, kind)
    kind = kind or 'info'
    -- Implement your UI notify event here. Example placeholder:
    TriggerClientEvent('fw:notify', target, msg, kind)
  end
  function M.Events.onPlayerLoaded(handler)
    RegisterNetEvent('esx:playerLoaded', function(_)
      handler(source)
    end)
  end

  return M
end

shared/adapters/qb.lua (QBCore)

Adapters = Adapters or {}

Adapters.qb = function()
  local QBCore = exports['qb-core']:GetCoreObject()

  local M = {
    meta = { name = function() return 'qbcore' end },
    Player = {}, Job = {}, Money = {}, Inv = {}, Events = {}
  }

  -- Player
  function M.Player.getBySrc(src) return QBCore.Functions.GetPlayer(src) end
  function M.Player.getStateId(p) return p.PlayerData.citizenid end
  function M.Player.getServerId(p) return p.PlayerData.source end
  function M.Player.getName(p)
    local pd = p.PlayerData
    return (pd.charinfo and (pd.charinfo.firstname .. ' ' .. pd.charinfo.lastname)) or GetPlayerName(pd.source)
  end

  -- Job
  function M.Job.getName(p) return p.PlayerData.job.name end
  function M.Job.getGrade(p)
    local g = p.PlayerData.job.grade
    return type(g) == 'table' and (g.level or g.grade) or g
  end
  function M.Job.onChange(handler)
    -- QBCore client event relays job update; mirror serverside via simple relay if needed.
    RegisterNetEvent('QBCore:Server:OnJobUpdate', function(job)
      handler(source, nil, job and job.name)
    end)
  end

  -- Money
  function M.Money.get(p, account) return p.PlayerData.money or 0 end
  function M.Money.add(p, account, amount, reason) p.Functions.AddMoney(account, amount, reason or 'fw') end
  function M.Money.remove(p, account, amount, reason) p.Functions.RemoveMoney(account, amount, reason or 'fw') end

  -- Inventory (qb-inventory or ox)
  local hasOX = GetResourceState('ox_inventory') == 'started'
  if hasOX then
    function M.Inv.addItem(p, name, count, meta) return exports.ox_inventory:AddItem(p.PlayerData.source, name, count, meta) end
    function M.Inv.removeItem(p, name, count, meta) return exports.ox_inventory:RemoveItem(p.PlayerData.source, name, count, meta) end
  else
    function M.Inv.addItem(p, name, count, meta) return p.Functions.AddItem(name, count, false, meta) end
    function M.Inv.removeItem(p, name, count) return p.Functions.RemoveItem(name, count) end
  end

  -- Events
  function M.Events.notify(target, msg, kind)
    TriggerClientEvent('fw:notify', target, msg, kind or 'info')
  end
  function M.Events.onPlayerLoaded(handler)
    RegisterNetEvent('QBCore:Server:PlayerLoaded', function()
      handler(source)
    end)
  end

  return M
end

shared/adapters/qbox.lua (QBOX / qbx_core)

Adapters = Adapters or {}

Adapters.qbox = function()
  -- QBOX typically exposes functions via exports only.
  -- If your fork also ships a GetCoreObject, swap accordingly.
  local QBX = exports['qbx_core']

  local M = {
    meta = { name = function() return 'qbox' end },
    Player = {}, Job = {}, Money = {}, Inv = {}, Events = {}
  }

  -- Player (QBOX uses Player with PlayerData similar to QBCore)
  function M.Player.getBySrc(src) return QBX:GetPlayer(src) end -- adjust if your API differs
  function M.Player.getStateId(p) return p.PlayerData.citizenid end
  function M.Player.getServerId(p) return p.PlayerData.source end
  function M.Player.getName(p)
    local pd = p.PlayerData
    return (pd.charinfo and (pd.charinfo.firstname .. ' ' .. pd.charinfo.lastname)) or GetPlayerName(pd.source)
  end

  -- Job
  function M.Job.getName(p) return p.PlayerData.job.name end
  function M.Job.getGrade(p)
    local g = p.PlayerData.job.grade
    return type(g) == 'table' and (g.level or g.grade) or g
  end
  function M.Job.onChange(handler)
    -- Some QBOX builds forward QBCore job events; if not, wire your own when setting jobs.
    RegisterNetEvent('QBCore:Server:OnJobUpdate', function(job)
      handler(source, nil, job and job.name)
    end)
  end

  -- Money
  function M.Money.get(p, account) return p.PlayerData.money or 0 end
  function M.Money.add(p, account, amount, reason)
    if p.Functions and p.Functions.AddMoney then p.Functions.AddMoney(account, amount, reason or 'fw')
    else QBX:AddMoney(p.PlayerData.source, account, amount, reason or 'fw') end
  end
  function M.Money.remove(p, account, amount, reason)
    if p.Functions and p.Functions.RemoveMoney then p.Functions.RemoveMoney(account, amount, reason or 'fw')
    else QBX:RemoveMoney(p.PlayerData.source, account, amount, reason or 'fw') end
  end

  -- Inventory (ox preferred on many QBOX servers)
  local hasOX = GetResourceState('ox_inventory') == 'started'
  if hasOX then
    function M.Inv.addItem(p, name, count, meta) return exports.ox_inventory:AddItem(p.PlayerData.source, name, count, meta) end
    function M.Inv.removeItem(p, name, count, meta) return exports.ox_inventory:RemoveItem(p.PlayerData.source, name, count, meta) end
  else
    -- fall back to qb-style if present
    if p and p.Functions and p.Functions.AddItem then
      function M.Inv.addItem(p, name, count, meta) return p.Functions.AddItem(name, count, false, meta) end
      function M.Inv.removeItem(p, name, count) return p.Functions.RemoveItem(name, count) end
    else
      function M.Inv.addItem() return false end
      function M.Inv.removeItem() return false end
    end
  end

  -- Events
  function M.Events.notify(target, msg, kind)
    TriggerClientEvent('fw:notify', target, msg, kind or 'info')
  end
  function M.Events.onPlayerLoaded(handler)
    -- Some QBOX builds reuse QBCore load events; if yours differs, relay from your login logic.
    RegisterNetEvent('QBCore:Server:PlayerLoaded', function()
      handler(source)
    end)
  end

  return M
end


Usage Examples

1) Paying a job bonus

RegisterNetEvent('myres:payBonus', function()
  local src = source
  local p = FW.Player.getBySrc(src)
  if not p then return end

  if FW.Job.getName(p) == 'delivery' then
    FW.Money.add(p, 'cash', 250, 'delivery-bonus')
    FW.Events.notify(src, 'Bonus paid (+$250).', 'success')
  else
    FW.Events.notify(src, 'You are not on duty as Delivery.', 'error')
  end
end)

2) Inventory grant with ox fallback already handled

local function giveStarter(src)
  local p = FW.Player.getBySrc(src)
  if p then FW.Inv.addItem(p, 'water', 2) end
end
FW.Events.onPlayerLoaded(giveStarter)


Anti‑Pattern Catalog (and Fixes)

Anti-patternWhy it bitesFix with adapter
Hard-coding core object (ESX = exports['es_extended']:getSharedObject() scattered everywhere)Locks you into ESX, tedious to migrateOnly call FW.*. Core resolution lives in adapter.
Storing framework player handle long-term (e.g., keep xPlayer in a table forever)Handles can go stale; references differ per frameworkRe-fetch via FW.Player.getBySrc(src) when you act, or cache by getStateId key and re-resolve.
Assuming identifiers are the same (ESX identifier vs QB/QBOX citizenid)Breaks DB relations/migrationsUse FW.Player.getStateId(p) and a crosswalk table during migrations.
Direct event names in business logic (esx:playerLoaded, QBCore:Server:PlayerLoaded)Fragile across forksSubscribe via FW.Events.onPlayerLoaded.
Mixed inventory assumptionsServers swap inventories oftenUse FW.Inv.* which detects ox_inventory first, then framework.
SQL schemas frozen to one frameworkaccounts, identifier, etc. divergeUse neutral columns (state_id, money_cash, money_bank) and migration helpers below.

SQL & Identifier Migration Notes (Quick Reference)

  • Primary person key:
    • ESX → identifier (license/steam)
    • QB/QBOX → citizenid
  • Neutral key in your tables: state_id (string). Store FW.Player.getStateId(p).
  • Money:
    • ESX: money (cash), accounts.bank, accounts.black_money
    • QB/QBOX: PlayerData.money.cash|bank
  • Minimal crosswalk (one‑time backfill):
-- Example: populate your neutral key from ESX users
UPDATE my_table t
JOIN users u ON u.identifier = t.identifier
SET t.state_id = u.identifier
WHERE t.state_id IS NULL;

-- Example: migrate to QB/QBOX where you have a mapping table esx_identifier→citizenid
UPDATE my_table t
JOIN id_map m ON m.esx_identifier = t.state_id
SET t.state_id = m.citizenid
WHERE m.citizenid IS NOT NULL;

Keep the crosswalk (id_map) only during the transition; future writes should always use state_id.


Testing Matrix & CI: Validate a Script Across Frameworks

You don’t need to boot a full CFX server in CI to catch most adapter issues. Stub exports and run unit tests for the contract surface.

1) Minimal test (Busted)

tests/fw_spec.lua

local function makeStub(framework)
  _G.Adapters = {}
  if framework == 'esx' then
    _G.exports = { ['es_extended'] = { getSharedObject = function()
      return {
        GetPlayerFromId = function(src)
          return {source = src, identifier = 'license:abc', getMoney = function() return 100 end,
                  addMoney = function() end, removeMoney = function() end,
                  getJob = function() return {name='mechanic', grade=2} end,
                  addAccountMoney=function() end, removeAccountMoney=function() end,
                  addInventoryItem=function() end, removeInventoryItem=function() end,
                  getName=function() return 'Alex ESX' end }
        end
      }
    end } }
    _G.GetResourceState = function(n) return n=='es_extended' and 'started' or 'missing' end
    dofile('shared/adapters/esx.lua')
  elseif framework == 'qbcore' then
    _G.exports = { ['qb-core'] = { GetCoreObject = function()
      return { Functions = { GetPlayer=function(src)
        return { PlayerData={source=src,citizenid='CITZ123',job={name='mechanic',grade=2},
                              money={cash=100,bank=500},charinfo={firstname='Alex',lastname='QB'}},
                 Functions={AddMoney=function() end, RemoveMoney=function() end, AddItem=function() return true end, RemoveItem=function() return true end} }
      end } }
    end } }
    _G.GetResourceState = function(n) return n=='qb-core' and 'started' or 'missing' end
    dofile('shared/adapters/qb.lua')
  elseif framework == 'qbox' then
    _G.exports = { ['qbx_core'] = setmetatable({}, { __index = function()
      return function(name) end
    end }) }
    _G.GetResourceState = function(n) return n=='qbx_core' and 'started' or 'missing' end
    dofile('shared/adapters/qbox.lua')
  end
  dofile('shared/fw.lua')
end

describe('FW contract', function()
  it('resolves player and money (esx)', function()
    makeStub('esx')
    assert.are.equal('esx', FW.meta.name())
    local p = FW.Player.getBySrc(1)
    assert.are.equal('license:abc', FW.Player.getStateId(p))
    assert.are.equal(100, FW.Money.get(p, 'cash'))
  end)

  it('resolves player and money (qbcore)', function()
    makeStub('qbcore')
    assert.are.equal('qbcore', FW.meta.name())
    local p = FW.Player.getBySrc(2)
    assert.are.equal('CITZ123', FW.Player.getStateId(p))
    assert.are.equal(100, FW.Money.get(p, 'cash'))
  end)
end)

2) GitHub Actions (luacheck + busted)

.github/workflows/lua.yml

name: Lua CI
on:
jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        lua: [ '5.4' ]
    steps:
      - uses: actions/checkout@v4
      - name: Install Lua & LuaRocks
        uses: leafo/gh-actions-lua@v10
        with: { luaVersion: ${{ matrix.lua }} }
      - name: Install rocks
        uses: leafo/gh-actions-luarocks@v4
      - run: luarocks install luacheck
      - run: luarocks install busted
      - name: Lint
        run: luacheck . --no-color --codes
      - name: Test
        run: busted -v

.luacheckrc (baseline)

std = 'lua54'
unused_args = false
max_line_length = 140
ignore = { '211', '212' } -- adjust for your style

For full integration tests, spin up your dev server once and smoke‑test with a tiny command set. CI stubs are sufficient to catch surface breaks.


Implementation Checklist

  • Drop shared/adapters/*.lua and shared/fw.lua into your resource
  • Replace all direct ESX/QBCore/QBOX calls in your code with FW.*
  • Keep only one persistence key: state_id in your tables
  • Configure inventory preference (ox first by default)
  • Add CI (luacheck + busted) and a minimal test for each call you use
  • Document any local deviations (fork‑specific events) at the top of your adapter file

Frequently Extended Surface (optional add‑ons)

  • FW.Duty.set(p, true|false) – wrap your duty toggles
  • FW.Permissions.has(src, aceOrGroup) – centralize admin/group checks
  • FW.Vehicle.spawn(model, coords) – hide framework spawn helpers

Keep the core contract tiny; put optional helpers in a separate module.


Tri‑way Mapping Quick Table

ConcernESXQBCoreQBOX (typical)
Core accessexports['es_extended']:getSharedObject()exports['qb-core']:GetCoreObject()No global; exports on qbx_core
Player by srcESX.GetPlayerFromId(src)QBCore.Functions.GetPlayer(src)exports.qbx_core:GetPlayer(src) (adjust if forked)
IdentifierxPlayer.identifierPlayerData.citizenidPlayerData.citizenid
Money addaddMoney / addAccountMoneyFunctions.AddMoneyFunctions.AddMoney or exports.qbx_core:AddMoney
Job namexPlayer.job.namePlayerData.job.namePlayerData.job.name
Player loaded eventesx:playerLoadedQBCore:Server:PlayerLoadedOften reuses QBCore events; fork‑specific

When in doubt on QBOX, inspect your fork’s qbx_core exports and wire accordingly.


Final Notes

  • Keep adapters boring: no side effects, no database calls.
  • Treat framework handles as opaque; extract what you need through the contract.
  • When you must diverge for a client, copy the adapter, not your business logic.

Read next: Converting FiveM Scripts Between ESX, QBCore & QBOX (Pillar Page)

Previous Article

Converting FiveM Scripts – ESX, QBCore, QBOX (Frame...

Next Article

SQL & Identifiers Migration: steam/license to citizenid

Table of Contents

Why an Adapter?How to Use (Drop‑in)Interface Contract (stable surface)FW.metaFW.PlayerFW.JobFW.MoneyFW.Inv (best‑effort; see Notes)FW.EventsDrop‑in Adapters (copy/paste)shared/fw.luashared/adapters/esx.luashared/adapters/qb.lua (QBCore)shared/adapters/qbox.lua (QBOX / qbx\_core)Usage Examples1) Paying a job bonus2) Inventory grant with ox fallback already handledAnti‑Pattern Catalog (and Fixes)SQL & Identifier Migration Notes (Quick Reference)Testing Matrix & CI: Validate a Script Across Frameworks1) Minimal test (Busted)2) GitHub Actions (luacheck + busted)Implementation ChecklistFrequently Extended Surface (optional add‑ons)Tri‑way Mapping Quick TableFinal Notes

More on This Topic

FiveM Frameworks Explained: Complete Guide to ESX, QBCore & QBOXESX vs QBCore vs QBOX: Technical Framework Comparison 2026QBCore Admin Commands — Complete FiveM ReferenceBest QBCore Scripts 2026: Essential Server StackBest QBOX Scripts 2026: Essential Resources for Your Server

Turn framework research into a launch-ready script stack

Use this guide to narrow the framework decision, then move into the core commercial hubs for verified scripts, curated bundles, and a faster server launch path.

Framework hub

Browse QBCore-ready scripts

Move into the QBCore landing page to compare verified scripts, framework fit, and install-ready products built for modern FiveM servers.

Open QBCore hub

Framework hub

Review the ESX script path

Use the ESX landing page to compare framework-specific resources, launch guidance, and premium products that fit ESX-first servers.

Open ESX hub

Premium catalog

Browse premium FiveM scripts

Move from research into the main shop to compare real products, framework labels, screenshots, and production-ready quality signals.

Open premium shop

Launch faster

Compare curated bundles

Bundles shorten the path from planning to launch by grouping the highest-leverage scripts into a cleaner commercial starting point.

View bundles

Disclosure: Some links below are affiliate links to FiveMX products. We may earn a commission at no extra cost to you.

Premium Scripts You Might Like

ESX Menu Design

ESX Menu Design

$5.49
ESX Inventory HUD V16

ESX Inventory HUD V16

$8.49
ESX Plugin For EasyAdmin

ESX Plugin For EasyAdmin

$4.49
ESX Enhanced Barber

ESX Enhanced Barber

$13.49

Free Scripts You Might Like

QBox Easter Egg Hunting

QBox Easter Egg Hunting

0 downloads
QBOX Garbage Job

QBOX Garbage Job

0 downloads
FiveM Marry Script (Marriage Mod)

FiveM Marry Script (Marriage Mod)

0 downloads

Related Articles

Converting FiveM Scripts – ESX, QBCore, QBOX (Frame...

Converting FiveM Scripts – ESX, QBCore, QBOX (Frame...

This is a code‑first, no‑fluff easy converting FiveM scripts guide that shows you exactly how to Convert FiveM Scripts between ESX, QBCore, QBOX...

August 15, 2025
QBox Framework Guide: Migrate from QBCore and Boost Performance (2026)

QBox Framework Guide: Migrate from QBCore and Boost Performance (2026)

QBox has firmly established itself as the natural successor to QBCore in the FiveM roleplay ecosystem.

March 31, 2026
QBOX vs QBCore: Which FiveM Framework Should You Choose?

QBOX vs QBCore: Which FiveM Framework Should You Choose?

Introduction: Why frameworks matter Your framework decides how fast you build features, how stable your city runs, and how easily you can scale. In FiveM...

September 5, 2025
FiveMX

Start building your server today.

Curated FiveM resources, instant delivery, free starter mods, and practical guides in one calm marketplace.

Browse the shopsupport@fivemx.com

Shop

  • Shop
  • FiveM Mods
  • All Products
  • Free Mods
  • Best Scripts & Mods
  • FiveM Scripts

Frameworks

  • QBCore Scripts
  • ESX Scripts
  • QBox
  • Standalone

Community

  • Blog
  • Support
  • Creators
  • Affiliate

Legal

  • Privacy Policy
  • Terms of Service
  • Refund Policy
  • Digital Delivery
  • Cookie Policy
  • GDPR Compliance
  • DMCA
  • Imprint
  • Editorial Policy

Server Templates

  • QBCore Server Template
  • ESX Server Template
  • NoPixel Server Template
  • Server Packs
  • Free Server Templates
  • Tebex Alternative
© 2026 FiveMX. All rights reserved.·FiveMX is not affiliated with Rockstar Games, Take-Two Interactive, or CFX.re. All trademarks are property of their respective owners.
DiscordDocs

No time to configure everything yourself?

Start with a pre-built, tested FiveM server pack. Framework-optimized, all scripts pre-installed.

Super ESX Server
esxstandalone

Super ESX Server

The Super ESX Server is one of the best FiveM server templates - over 1.000 purchases! Want to know why we call it our Super Server? Check out our video to find out some of the basics details of the world. Update 10 is included, make sure to install v7 first and then use content of v10 yo

$228.32
ESX Server Base (by RibSosay)
esxstandalone

ESX Server Base (by RibSosay)

Prebuilt FiveM server with ESX framework GUARANTEE : We offer a guarantee ensuring compatibility with your setup.

$53.99
View all server packs