Store small resource settings without escaping the sandbox
Use LoadResourceFile and SaveResourceFile for a small JSON document owned by your resource. Keep the filename fixed, validate the data, and check the write result. Use a database for balances, inventory, concurrent updates, or records that need transactions.
The example below stores an informational maintenance banner. It does not enforce admission, take a server offline, or replace a backup system. Only the server console can change it.
Create a server-only settings resource
Create resources/[local]/doc_settings/fxmanifest.lua:
fx_version 'cerulean'
game 'gta5'
server_script 'server.lua'Create settings.json:
{"banner":"Welcome to the development server"}Create server.lua:
local resourceName = GetCurrentResourceName()
local filename = 'settings.json'
local settings
local function valid(value)
return type(value) == 'table'
and type(value.banner) == 'string'
and #value.banner <= 160
and not value.banner:find('%c')
end
local raw = LoadResourceFile(resourceName, filename)
if raw and #raw <= 4096 then
local ok, decoded = pcall(json.decode, raw)
if ok and valid(decoded) then settings = { banner = decoded.banner } end
end
if not settings then
print('[doc_settings] Invalid settings.json. Repair it before updating the banner.')
end
RegisterCommand('docbanner', function(playerId, args)
if playerId ~= 0 then return end -- Console only, even if a player has ACE access.
if not settings then return end
if #args == 0 then
print(('Banner: %s'):format(settings.banner))
return
end
local candidate = { banner = table.concat(args, ' ') }
if not valid(candidate) then
print('Use at most 160 bytes, without control characters.')
return
end
local encoded = json.encode(candidate)
if not SaveResourceFile(resourceName, filename, encoded, #encoded) then
print('[doc_settings] Write failed. The in-memory setting was not changed.')
return
end
settings = candidate
print('Banner saved. Restart the resource and run docbanner to verify persistence.')
end, true)Do not list settings.json under files, which would make it part of the client download. In the server console, run refresh, ensure doc_settings, then docbanner Maintenance starts at midnight. Run restart doc_settings and docbanner; the banner should persist.
What the sandbox allows
The official sandbox documentation defines resource filesystem boundaries. The safe default is to write within the current resource; cross-resource writes are restricted. SaveResourceFile is not a way around those restrictions. An access-denied error is a reason to inspect the ownership and destination, not disable protections or shell out.
Never accept a filename, resource name, directory traversal, or source code from a network event and pass it into a file-writing function. Do not store executable Lua or JavaScript as user-editable configuration. Keep credentials server-side and out of streamed/shared files.
| Storage need | Better fit |
|---|---|
| Small resource-owned settings | Validated JSON file, backed up with server data |
| Small resource key/value preferences | Resource KVP APIs; choose the correct client or server context |
| Shared balances or inventory | Database with transactions and server-side validation |
| A setting clients need to display | Publish only the safe value through a deliberate API or event, not the complete file |
Test and deployment limitations
Test invalid JSON, a missing file, a too-long banner, and a read-only resource directory. A player entering docbanner must never be able to mutate configuration. Keep a backup of the file before changing deployment permissions.
This example has one writer and synchronous updates, with no yield between reading the current value and saving its replacement. It is not a transactional storage layer or a crash-safe atomic replacement scheme. A crash or interrupted filesystem write can still damage a file. The next startup refuses an invalid configuration rather than silently overwriting it.
In containers or artifact-based deployments, a file written into a disposable resource directory may disappear on redeploy. Mount persistent storage deliberately and test both restart and redeploy behavior. Continue with backups, database access, and server permissions.