ESX & QBCore Scripts Together — Quasar Framework (qs-core) | Quasar Store | Quasar Store
Documentation
ESX & QBCore Compatibility
Run ESX and QBCore scripts on one FiveM server with Quasar Framework (qs-core): es_extended and qb-core bridges share one player, money, jobs and items.
Quasar Framework (qs-core) runs ESX scripts and QBCore scripts on the same FiveM server, at the same time, without editing them. Two compatibility bridges ship in the [bridge] folder — es_extended and qb-core — and they answer exactly where a script expects the real frameworks to be. Both bridges read and write one shared player: the money an ESX job pays is the money a QBCore shop charges, the job a QBCore script sets is the job an ESX script reads, and an item added with xPlayer.addInventoryItem shows up in Player.PlayerData.items.
Why it matters: the FiveM roleplay market is split in two. A large share of scripts is written for ESX (ESX Legacy, es_extended), another large share for QBCore (qb-core), and choosing a framework used to mean giving up the other half — or paying for conversions and maintaining forks. With Quasar Framework you forget about framework limits and pick scripts for what they do, not for the framework they were written for.
The [bridge] folder holds seven small resources. Each one takes the name of a well-known FiveM resource and answers its API on top of Quasar Framework:
Resource
Answers as
What it provides
es_extended
ESX Legacy (version 1.13.4)
The ESX object, xPlayer, ESX callbacks, commands, usable items, ESX events and the users table.
qb-core
QBCore (version 1.2.0)
The QBCore object, the Player object, QBCore.Shared tables, callbacks, commands, usable items and QBCore events.
esx_society
esx_society
Society money accounts.
qb-management
qb-management
Job and gang funds.
qb-vehiclekeys
qb-vehiclekeys
Vehicle keys, forwarded to qs-corevehiclekeys.
progressbar
progressbar
Progress bars, drawn by Quasar Framework.
LegacyFuel
LegacyFuel
GetFuel / SetFuel and fuel consumption.
Both frameworks run at once.server.cfg starts the bridges last, with ensure [bridge] after every [core] and [addons] resource, the character flow and [maps]. es_extended and qb-core each listen to Quasar Framework's own events independently, so neither depends on the other and neither has to be switched on or off.
Because the bridges take the resource names es_extended and qb-core, the real ESX and QBCore cannot run next to them — and they do not need to.
Fired after the core object changes (SetMethod, SetField, AddJob, AddItem...), so scripts can refresh their copy.
Scripts that support both frameworks and detect them automatically will find both started and use whichever they check first. Either choice works, because both bridges talk to the same player. If the script has a framework setting, you can also set it to ESX or QBCore yourself.
Quasar Framework keeps one character per player. The bridges do not copy it — they read and write it, so every script sees the same values at the same moment:
Data
ESX script sees
QBCore script sees
Character id
xPlayer.identifier, xPlayer.getIdentifier() (the citizenid)
And a QBCore script on the same server, reading the same character a moment later:
lua
-- server.lua of a QBCore scriptlocal QBCore = exports['qb-core']:GetCoreObject()
QBCore.Commands.Add('whoami', 'Show your character', {}, false, function(source)local Player = QBCore.Functions.GetPlayer(source)
local data = Player.PlayerData
print(data.citizenid) -- the same id ESX sees as xPlayer.identifierprint(data.job.name, data.job.grade.level) -- police 1print(data.money.bank) -- includes the 2500 the ESX script paidlocal kit = Player.Functions.GetItemByName('repairkit')
print(kit and kit.amount) -- 1end)
The events line up too: when the ESX script calls setJob, ESX scripts receive esx:setJob and QBCore scripts receive QBCore:Server:OnJobUpdate from the same change. When it pays the bonus, QBCore scripts receive QBCore:Server:OnMoneyChange.
The es_extended bridge reproduces the ESX Legacy API that scripts use day to day. Everything below works on Quasar Framework as it does on ESX; the few functions that exist only as placeholders are listed in What is not covered.
Chat command (one name or a list). user commands are open to everyone; any other group requires the ACE group.<group>, group.admin or command. Argument types number, player / playerId (accepts me), string / any and weapon are parsed, validate is honoured, and the callback receives (xPlayer, args, showError). A chat suggestion is added.
Items
Function
What it does
ESX.RegisterUsableItem(item, cb)
Makes an item usable. When a player uses it from the inventory, cb(source, itemName) runs.
ESX.UseItem(source, item)
Runs an item's registered callback.
ESX.GetItems()
The item catalogue, always current.
ESX.Items
The catalogue as it was when the bridge started (label, weight).
ESX.GetItemLabel(item)
The item's label.
Jobs
Function
What it does
ESX.GetJobs()
Every job in ESX shape, always current: label and grades["0"] = { job_name, grade, name, label, salary }.
ESX.Jobs
The same table, as it was when the bridge started.
The bridge also answers two things character scripts rely on: the server callback esx_identity:registerIdentity (creates and loads a character from ESX identity data, then fires esx_identity:completedRegistration) and the server event esx:playerLogout, which logs the character out.
money is cash, bank is the bank account, and any other name is an extra account saved with the character — the same extra accounts QBCore scripts see as money types. Amounts are rounded down; zero or negative amounts are ignored.
Through the real inventory, with weight and slots respected. Returns true / false and fires esx:addInventoryItem / esx:removeInventoryItem on the client.
setInventoryItem(name, count)
Adds or removes the difference.
canCarryItem(name, count) / hasItem(name, count)
Weight and space check / ownership check.
canSwapItem(itemA, countA, itemB, countB)
Whether the player can carry countB of itemB.
getWeight() / getMaxWeight()
Current carried weight / the ESX maximum weight.
Job
Method
What it does
getJob()
The current job in ESX shape.
setJob(name, grade)
Sets the job. A job that does not exist yet is created with grades 0 employee, 1 experienced, 2 advanced and 3 boss; an unknown grade falls back to the lowest grade.
ESX.PlayerData with identifier, citizenid, job, accounts, inventory (ESX shape, kept in sync with the inventory), money, metadata, firstName, lastName, dateofbirth, sex, maxWeight. Plus ESX.PlayerLoaded, ESX.IsPlayerLoaded(), ESX.GetPlayerData() and ESX.SetPlayerData(key, value).
ESX.UI.Menu.RegisterType, Open, Close, CloseAll, GetOpened, GetOpenedMenus, IsOpen, and the menu methods close, update, refresh, setElement, setElements, setTitle, removeElement. Install a menu resource such as esx_menu_default, exactly as you would on ESX.
After esx_identity:registerIdentity creates a character.
The bridge also handles esx:showNotification, esx:showAdvancedNotification and esx:showHelpNotification sent from the server, and esx:triggerServerCallback / esx:serverCallback for callbacks.
The qb-core bridge reproduces the QBCore API. QBCore.Functions.GetPlayer rebuilds PlayerData from Quasar Framework on every call, so each call returns the current balance, job and items.
Registers a chat command with its suggestion. permission is checked like HasPermission (user = everyone); with argsrequired, missing arguments are refused; cb(source, args, raw).
QBCore.Commands.Refresh(source)
Re-sends the command suggestions to a player (done automatically when a character loads).
On the server: every item of Quasar Framework in QBCore shape (name, label, weight, type, image, unique, useable, description...). Items you add to [bridge]/qb-core/shared/items.lua are registered in Quasar Framework when the server starts.
QBCore.Shared.Jobs
On the server: every job, grades in QBCore shape (['0'] = { name, payment, isboss }). Jobs in [bridge]/qb-core/shared/jobs.lua are registered in Quasar Framework when the server starts.
QBCore.Shared.Gangs
Gangs from [bridge]/qb-core/shared/gangs.lua plus the gangs of Quasar Framework.
QBCore.Config is there for scripts that read it (MaxPlayers follows sv_maxclients). The values that actually shape the server — starting money, paychecks, autosave — come from Quasar Framework's own config. See Configuration.
The bridge also handles QBCore:Notify and QBCore:Client:Notify on the client, and QBCore:ToggleDuty, QBCore:Server:SetMetaData (hunger, thirst, stress) and the callback events on the server.
Ecosystem bridges: society, keys, progress and fuel#
Many ESX and QBCore scripts also call a handful of popular companion resources. Five of them are answered by small bridges:
Quasar Framework's progress bar, with the animation, props and movement lock from data. X cancels when canCancel is set.
LegacyFuel
Client exports GetFuel(vehicle) and SetFuel(vehicle, fuel).
Fuel kept on the vehicle (0–100) and consumed while the engine runs, faster at high RPM; the engine stops at 0. The HUD fuel gauge reads it.
ESX ESX.Progressbar and QBCore QBCore.Functions.Progressbar use the same progress bar. How each of these connects to the rest of the server is in Integrations.
Quasar Framework stores characters in its own players table. The bridges add the ESX and QBCore tables scripts query most, so their SQL keeps working where it can:
Table
Created by
What it holds
players
Quasar Framework ([core]/qs-core/sql/qscore.sql)
One row per character: citizenid, license, name, charinfo, money, job, inventory, metadata, position, skin, is_dead, cid. The JSON inside uses Quasar Framework's shapes.
users
es_extended, on start
The ESX view of each character, keyed by citizenid: accounts, job, job_grade, position, firstname, lastname, dateofbirth, sex, skin, inventory, metadata. Written from Quasar Framework when a character loads and on every save (every 5 minutes, on logout and on disconnect).
Created with the ESX columns so queries do not fail; Quasar Framework vehicles live in vehicles.
society_accounts
esx_society, on start
name, money.
management_funds
qb-management, on start
job_name, amount, type (job or gang).
For vehicle lists, scripts can call exports['qs-core']:GetCitizenVehicles(citizenid) (every row of vehicles for a character) or exports['qs-core']:GetPlayerVehiclesQBShape(citizenid) (the same rows in QBCore player_vehicles shape).
Read the script's requirements and install its dependencies as they are. oxmysql and ox_lib are already installed. Target, menu and input resources — ox_target, qb-target with PolyZone, qb-menu, qb-input, or an ESX menu such as esx_menu_default for ESX.UI.Menu — go in as the script's own documentation says. Do not install es_extended, qb-core or the other names in [bridge]: the bridges already are those resources.
Put the script in your resources folder
Copy the script's folder anywhere under resources, for example in a [scripts] folder of your own. Leave the script's code as it is.
Start it after the bridges
In server.cfg, ensure the script and its dependencies afterensure [bridge]:
Scripts that start before [bridge] cannot find es_extended or qb-core.
Import its SQL
If the script ships an .sql file for its own tables, import it into your database. ESX scripts often also insert rows into ESX's items, jobs and job_grades tables: Quasar Framework does not read those tables, so add the same items and jobs in the next two steps instead. If the file adds columns to users, remember that users is written from Quasar Framework and is not read back (see Database compatibility).
Add its items
Every item the script gives or checks must exist in the item catalogue — getInventoryItem returns nil for an item that does not exist, and an inventory cannot hold it. Use whichever format the script ships; weights are in grams:
Add the items to the base table in [core]/qs-core/shared/items.lua:
Add the jobs the script uses to [core]/qs-core/shared/jobs.lua, or paste the QBCore job entries into [bridge]/qb-core/shared/jobs.lua. A job a script sets that exists nowhere is created on the fly with generic grades and no salary (ESX: grades 0–3, QBCore: 0–4), so defining it yourself gives it the right labels and pay. QBCore gangs go in [bridge]/qb-core/shared/gangs.lua.
A job in [core]/qs-core/shared/jobs.lua, inside the Jobs table:
lua
Restart and test
Restart the server so the catalogue is read again. In game, give yourself the script's items and job with the admin commands — /giveitem <id> <item> [count] and /setjob <id> <job> [grade] — and try every feature. Keep the server console and the F8 console open: the ESX bridge prints a warning when a script calls a server callback that nobody registered.
Writing your own resource? You can call ESX or QBCore functions as shown on this page, or Quasar Framework's own exports directly. See Commands and Exports.
The bridges cover the API that ESX and QBCore scripts use in practice. These parts are outside it:
Qbox-only scripts. Scripts written only for Qbox (qbx_core) are not supported. Scripts that support QBCore run through the qb-core bridge.
Direct inventory exports. Scripts that call exports['qb-inventory'] or exports['ox_inventory'] directly are not covered. Items, stashes and usable items go through the framework functions above.
Raw SQL on character tables. Writes to users are not read back. Queries on players see Quasar Framework's JSON shapes, and a change written to an online character is replaced by the next autosave.
Vehicle tables of ESX and QBCore.player_vehicles (QBCore) is not created and owned_vehicles (ESX) stays empty, so garage or dealership scripts that read those tables with SQL do not see Quasar Framework vehicles. Use the built-in garages and dealership, or the vehicle exports above.
ESX weapon loadouts. Weapons in Quasar Framework are inventory items (weapon_pistol...). xPlayer.getLoadout() returns {}, hasWeapon() returns false, getWeapon() returns nil and weapon components and tints are not implemented. xPlayer.addWeapon() gives a GTA weapon that is not an inventory item and is not saved; give the weapon item with addInventoryItem instead.
ESX placeholders.ESX.CreatePickup does nothing (it prints a warning). ESX.SavePlayer and ESX.SavePlayers only run their callback — Quasar Framework saves on its own. ESX.UI.HUD functions do nothing and ESX.Scaleform is empty. xPlayer.setName() does nothing, xPlayer.setGroup() lasts for the session only (use /setgroup to keep a group), and the xPlayer.group field reads user — use xPlayer.getGroup().
ESX weight.xPlayer.getMaxWeight() returns 24000, from Config.MaxWeight = 24 in [bridge]/es_extended/shared/config/main.lua, while the inventory's own limit is 50 kg. canCarryItem checks the real limit; set Config.MaxWeight = 50 if a script compares weights itself.
ESX functions not present.ESX.GetWeapon, ESX.GetWeaponList, ESX.GetWeaponLabel, client callbacks (ESX.TriggerClientCallback), await-style callbacks, ESX.TextUI / ESX.HideUI, the ESX.OpenContext family, ESX.SearchInventory and ESX.OneSync helpers other than SpawnVehicle / DeleteVehicle. Vehicle properties passed to ESX.OneSync.SpawnVehicle are stored on the vehicle but not applied. On xPlayer: hasWeaponComponent, setWeaponTint, getWeaponTint, , , .
QBCore functions not present. Return-value (await) TriggerCallback, routing bucket functions, CreateVehicle / CreateAutomobile, ToggleOptin, IsWhitelisted, IsLicenseInUse, PrepForSQL; Player.Functions.Logout, SetInventory, AddRep / RemoveRep / GetRep, SetCreditCard, GetCardSlot; QBCore.Player.Login, Logout, CreatePlayer, . does nothing — use the function of the offline player object. is empty.
QBCore events not emitted.QBCore:Client:OnPlayerUnload and QBCore:Client:OnMoneyChange; QBCore:Server:OnPlayerUnload fires on disconnect, not on /logout.
QBCore character details.cid is always 1, and characters have no phone number of their own (charinfo.phone reads 0000000000). On the client, QBCore.PlayerData.metadata holds the character's metadata without the QBCore default keys, which are only added on the server.
ESX add-on resources.esx_addonaccount, esx_datastore and esx_addoninventory are not provided, and neither esx_society nor qb-management includes a boss menu.
Can I run ESX and QBCore scripts on the same FiveM server?
Yes — that is what Quasar Framework is built for. The es_extended and qb-core bridges run together and both talk to the same player, so an ESX script and a QBCore script share the same money, job, items and metadata.
Do I need to edit my ESX or QBCore scripts?
No. Scripts that use the framework object, its callbacks, its events and its usual helpers run as they are. What you do once per script is add its items and jobs to the catalogue and start it after [bridge].
Do I still need to convert ESX scripts to QBCore, or QBCore scripts to ESX?
No. ESX to QBCore conversion — and QBCore to ESX — is no longer needed: each script runs on the bridge for the framework it was written for, and both bridges share one player.
Does it work with Qbox?
Scripts that support QBCore work through the qb-core bridge, including many that also support Qbox. Scripts written only for Qbox (qbx_core) are not supported.
Can I use ox_inventory?
No. Quasar Framework's inventory is qs-coreinventory, or Quasar Store's advanced qs-inventory (see Integrations). Scripts that call ox_inventory exports directly are not covered; if a script lets you choose its inventory, choose the ESX or QBCore option so it goes through the bridge.
Should I install esx_identity, esx_multicharacter or qb-multicharacter?
No. Character selection and creation are handled by qs-coremulticharacter. The es_extended bridge already answers esx_identity:registerIdentity and esx:playerLogout, so installing the real esx_identity or another multicharacter resource would put two character systems on the same player.
Can I install the real es_extended or qb-core next to it?
No. The bridges already answer as es_extended and qb-core, and two resources cannot share a name. Running the real frameworks would also load a second core for the same players.
Does running two framework bridges slow the server down?
The bridges react to Quasar Framework events instead of polling, and nothing in them runs every frame while players are idle. The only timers are a once-a-second death check on the client for ESX scripts and the LegacyFuel tick, once a second while you drive.
Which ESX and QBCore versions are covered?
The es_extended bridge follows the ESX Legacy API and reports version 1.13.4; the qb-core bridge follows the QBCore API and reports 1.2.0 from GetCoreVersion().
Where do ESX scripts store per-player data?
Wherever they did before — usually their own tables, keyed by xPlayer.identifier. On Quasar Framework that identifier is the character's citizenid, so the data belongs to the character.
GetPlayersInArea
GetVehiclesInArea
IsSpawnPointClear
GetVehicleInDirection
GetVehicleProperties
SetVehicleProperties
ESX.Game.Utils.DrawText3D
Add them to BridgeItems in [bridge]/es_extended/config/items.lua. They are created in Quasar Framework when the server starts (fields label, weight, useable, description, unique, image):
Paste the script's QBCore item entries into [bridge]/qb-core/shared/items.lua. They are registered in Quasar Framework when the server starts, and they are also available to the script on the client: