Skip to Content
ScriptingExports
Report an error
Open in ChatGPTOpen in Claude

Exports

Exports allow resources to share functions with other resources. The server example below uses ESX .

Defining Exports

Server Export

-- server.lua exports('getPlayerData', function(source) local xPlayer = ESX.GetPlayerFromId(source) return xPlayer end)

Client Export

-- client.lua exports('showNotification', function(message) -- Show notification end)

Consuming Exports

Server

local playerData = exports['myresource']:getPlayerData(source)

Client

exports['myresource']:showNotification('Hello!')

Namespacing

Use resource name as namespace:

-- Good exports['qb-core']:GetPlayer(source) -- Bad exports:GetPlayer(source)

Identifying the Caller

Inside an export, GetInvokingResource() returns the name of the resource that called it. It returns nil when there is no invoking script runtime (native , source ). Use it to allow-list callers and to key per-caller state, then drop that state when the caller stops. Listening to onResourceStop for another resource’s name is reliable, because your own resource is still running. Cfx’s own chat resource uses this pattern for registerMessageHook.

-- server.lua (provider resource) local allowedCallers = { ['my-shop'] = true } local hooks = {} exports('registerHook', function(fn) local caller = GetInvokingResource() if not caller or not allowedCallers[caller] then return false end hooks[caller] = fn return true end) AddEventHandler('onResourceStop', function(resourceName) -- Drop the registration of a caller that stopped hooks[resourceName] = nil end)

Error Handling Patterns

Checking Export Availability

Before calling an export, check if the resource is started to avoid errors.

if GetResourceState('ox_inventory') == 'started' then local items = exports.ox_inventory:Items() else print('ox_inventory is not started') end

Protected Calls (pcall)

Use pcall when the export might fail internally or return unexpected data.

local success, result = pcall(function() return exports['myresource']:riskyOperation() end) if success then print('Result:', result) else print('Export call failed:', result) end

Versioning Strategies

When updating exports, maintain backward compatibility.

Strategy A: Argument Inspection

Check arguments inside the export to support multiple formats.

exports('giveItem', function(target, item, count) if type(target) == 'table' then -- Handle new object-style arguments count = target.count item = target.item target = target.source end -- ... implementation end)

Strategy B: Versioned Names

Create new exports for breaking changes.

exports('giveItem', function(...) end) -- v1 (Deprecated) exports('giveItem_v2', function(opts) end) -- v2

Testing Exports

Create a test suite script to verify your exports behave as expected.

-- tests.lua CreateThread(function() Wait(1000) -- Wait for resources to load print('Testing exports...') local result = exports['myresource']:calculate(5, 5) assert(result == 10, 'Math export failed') print('Tests passed!') end)

Documentation Standards

Document your exports clearly in your README or code comments so other developers know how to use them.

--- @export getBalance --- Retreives the current bank balance for a player --- @param source number The player server ID --- @param accountType string "bank" or "cash" --- @return number The balance, or 0 if not found exports('getBalance', function(source, accountType) -- ... end)

Best Practices

  • Use descriptive names: getUser vs get.
  • Return values: Always return something (even false or nil) to confirm execution.
  • Async consideration: Remember exports are synchronous. For heavy tasks, use callbacks or events.