Exports and dependencies
Share code between FiveM resources with exports, call framework functions, declare dependencies in fxmanifest, import @resource files and bridge frameworks.
Por enquanto, esta documentação está em inglês.
Resources are isolated from each other: a global variable in one resource doesn’t exist in another. To share functionality you use exports (call a function in another resource) and shared files (load another resource’s file into yours with @resource/path). Dependencies make sure the resource you rely on is there and starts first.
Exports
Defining an export
local accounts = {}
exports('getBalance', function(identifier)
return accounts[identifier] or 0
end)
exports('addBalance', function(identifier, amount)
if type(amount) ~= 'number' or amount <= 0 then return false end
accounts[identifier] = (accounts[identifier] or 0) + amount
return true
end)exports(name, fn) works in Lua without any manifest entry. Exports are per side: a server export is only callable from server scripts, a client export only from client scripts.
Calling an export
local balance = exports.banking:getBalance(identifier)
exports['banking']:addBalance(identifier, 500)Use the bracket form when the resource name has a dash: exports['qb-core']:GetCoreObject(). Note the colon: exports are called like methods.
If the resource isn’t started, the call errors with No such export getBalance in resource banking. Guard with GetResourceState('banking') == 'started' if it’s optional.
JavaScript and C#
exports('getBalance', (identifier) => accounts[identifier] ?? 0);
const balance = exports.banking.getBalance(identifier);C# resources call them through Exports["banking"].getBalance(identifier).
Using a framework through exports
Frameworks expose their core object or functions as exports:
-- QBCore
local QBCore = exports['qb-core']:GetCoreObject()
local Player = QBCore.Functions.GetPlayer(source)
-- Qbox
local player = exports.qbx_core:GetPlayer(source)
exports.qbx_core:AddMoney(source, 'cash', 100, 'fishing')
-- ESX Legacy
local ESX = exports['es_extended']:getSharedObject()
local xPlayer = ESX.GetPlayerFromId(source)
-- ox_inventory
exports.ox_inventory:AddItem(source, 'water', 1)See the Frameworks pages for more.
Importing files with @resource
A manifest can load another resource’s file as if it were yours:
shared_script '@ox_lib/init.lua'
server_script '@oxmysql/lib/MySQL.lua'@ox_lib/init.luasets up thelibglobal andcachein your resource.@oxmysql/lib/MySQL.luagives you theMySQLglobal.@qbx_core/modules/lib.luaand@qbx_core/modules/playerdata.luaare Qbox helpers.@es_extended/imports.luasets upESXin your resource.
The file runs inside your resource’s environment, so this is faster than calling an export for every small helper. The other resource must be present (and for ox_lib, started first).
Dependencies
List what your resource needs in the manifest:
dependencies {
'oxmysql',
'ox_lib',
'/onesync', -- requires OneSync
'/server:12913', -- requires at least this server artifact
'/gameBuild:3095', -- requires at least this game build (name like 'h4' works too)
}FXServer then:
- starts listed resources before yours, and refuses to start yours if one is missing,
- refuses to start it if the server or game requirements aren’t met, with a clear error.
This is much more reliable than hoping ensure order in server.cfg is right. The /server:, /onesync, /gameBuild:, /policy: and /native: forms come from the official manifest reference. The build numbers above are just examples: use the ones your resource really needs.
provide: replacing another resource
provide 'mysql-async'Tells FXServer this resource satisfies dependencies on mysql-async. oxmysql uses it so old resources that depend on mysql-async or ghmattimysql keep working. Only use provide if you really implement the same API.
Writing framework independent resources
If you want your resource to work on QBCore, Qbox and ESX, don’t sprinkle framework calls everywhere. Put them behind a small bridge:
Bridge = {}
local function detect()
if GetResourceState('qbx_core') == 'started' then return 'qbx' end
if GetResourceState('qb-core') == 'started' then return 'qb' end
if GetResourceState('es_extended') == 'started' then return 'esx' end
return 'standalone'
end
local fw = detect()
local QBCore = fw == 'qb' and exports['qb-core']:GetCoreObject() or nil
local ESX = fw == 'esx' and exports['es_extended']:getSharedObject() or nil
function Bridge.addMoney(src, amount)
if fw == 'qbx' then
return exports.qbx_core:AddMoney(src, 'cash', amount)
elseif fw == 'qb' then
local p = QBCore.Functions.GetPlayer(src)
return p and p.Functions.AddMoney('cash', amount)
elseif fw == 'esx' then
local x = ESX.GetPlayerFromId(src)
if x then x.addMoney(amount) return true end
end
return false
endThe rest of your code calls Bridge.addMoney(src, 100) and never cares which framework runs. Paid resources on Tebex use exactly this pattern, often leaving the bridge files open under escrow_ignore. (Qbox also ships QBCore compatibility, so many qb-core calls work on Qbox too.)
Load order inside a resource
shared_scriptsload first, on both sides.- Then
client_scripts(client) orserver_scripts(server), in the order listed. - Globs (
client/*.lua) load in alphabetical order.
So put config.lua and library imports at the top of shared_scripts.
Common mistakes
No such export: wrong resource name (check the folder name), resource not started, calling a server export from the client (or the reverse), or the export was renamed in a new version.attempt to index a nil value (global 'lib'): you forgotshared_script '@ox_lib/init.lua'.- Circular dependencies: A depends on B and B on A. Move shared code into a third resource.
- Exporting huge tables every call: exports copy data between resources. Return what’s needed.
Next: Debugging.
