Engineering
Designing a config.lua people can actually use
Design FiveM script configs well: what belongs in config vs code, shared vs server-only config (secrets), grouping and naming, sensible defaults, validation at startup, vectors and job tables, framework/inventory switches, comments in English, and keeping configs editable under escrow.
Overview
The config is the part of your script every server owner touches. A good one makes installation boring — in the best way. A bad one produces support tickets, leaked webhooks and servers where a typo in a coordinate crashes the resource on start.
Shared vs server-only config
shared_script 'config.lua' -- sent to clients
server_script 'config_server.lua' -- never leaves the server
escrow_ignore { 'config.lua', 'config_server.lua', 'locales/*.json' }Everything in a shared or client file is downloaded by every player and readable. Discord webhooks, API keys and payout amounts belong in the server-only file — see anticheat basics.
A clear shape
Config = {}
Config.Debug = false
Config.Framework = 'auto' -- 'auto' | 'esx' | 'qb' | 'qbx'
Config.Inventory = 'ox' -- 'ox' | 'qb'
Config.Garages = {
legion = {
label = 'Legion Square',
coords = vec3(215.8, -810.1, 30.7),
spawn = vec4(229.7, -800.1, 30.5, 157.8),
jobs = nil, -- nil = everyone
},
}
Config.Impound = {
fee = 250,
jobs = { police = 2 }, -- job = minimum grade
}- Group by feature, not by type.
- Use
vec3/vec4for positions — readable and fast. - Keep English comments short and on the settings people change.
- Avoid functions in configs unless they are explicit hooks (e.g.
Config.CanUse = function(src) ... end).
Validate at startup
for id, g in pairs(Config.Garages) do
assert(type(g.label) == 'string', ('Config.Garages.%s.label must be a string'):format(id))
assert(type(g.spawn) == 'vector4', ('Config.Garages.%s.spawn must be vec4(x, y, z, heading)'):format(id))
endA clear message at start beats a nil error an hour later in the middle of a scene. Annotate config shapes for editor help — see Lua annotations.
Defaults that work
Ship with coordinates, prices and toggles that work on a fresh server, Config.Debug = false, and translations in a locale file rather than in the config — see localization. Document every option in your README — see script documentation.
Frequently asked questions
What should go in a FiveM config.lua?
Values server owners change: locations, prices, jobs, toggles. Logic stays in code.
Where should I put webhooks and API keys?
In a server-only config file loaded with server_script, never in shared or client files.
How do I keep configs editable in escrowed resources?
List them in escrow_ignore in the fxmanifest.
Should configs contain translations?
Better in locale files, so translators do not need to touch the config.
Need this built, not just explained?
Ten years of FiveM work, from Lua to NUI
Custom resources, React NUI, ESX / QBCore / Qbox integration, OneSync performance audits and security reviews — plus the websites and SEO around your server brand.
Related guides
- EngineeringTranslating FiveM scripts into other languagesWith ox_lib, add ox_lib 'locale' to the fxmanifest, put strings in locales/en.json (and other languages), call locale('key', ...) in code, and server owners choose the language with setr ox:locale de. ESX Legacy uses Translate/TranslateCap with Lua locale tables; QBCore uses Locale:new and Lang:t('key'). Use placeholders instead of string concatenation, fall back to English, and send UI strings to NUI in one message.
- BusinessWriting documentation for FiveM resourcesStructure docs as: what it does, requirements (dependencies with versions), installation (exact steps, SQL, ensure order), configuration (every option with default and example), usage (commands, keybinds, items), developer API (exports and events with parameters), troubleshooting (common errors and fixes), FAQ and a changelog. Keep it in the resource as a README and publish a searchable docs site for bigger products.
- EngineeringTyping your FiveM Lua with annotationsAnnotate functions with ---@param name type and ---@return type, describe table shapes with ---@class and ---@field, restrict strings with ---@alias, and mark variables with ---@type. The language server then checks calls and completes fields. Annotations are comments, so they cost nothing at runtime. Start with configs and shared data shapes — they catch the most bugs.
- BusinessAsset escrow: protecting and buying FiveM resourcesAsset escrow encrypts Lua, YFT, YDD and YDR files uploaded to the Cfx.re Portal and delivers them through Tebex. An escrowed resource only starts on servers whose owner holds the entitlement; otherwise the console shows “You lack the required entitlement”. Sellers leave config files editable with escrow_ignore. NUI files are not encrypted. Re-uploading replaces the version on the seller’s account, and subscription assets stop working when the subscription ends.