What "installing a script" actually means
In FiveM, a script is not an app you double-click. It is a resource: a folder of Lua, JavaScript, or C# code plus a manifest file that tells the server what to load and in what order. Installing a resource means three things happen correctly: the files land in the right place, the server is told to start them, and any external requirements (a database table, a dependency, an authorized asset) are satisfied first.
Most "my script doesn't work" problems are not bugs in the script. They are ordering and wiring problems. Get the mechanics right and the vast majority of install failures disappear.
The resources folder and [categories]
Every FiveM server has a resources directory inside your server data folder (often called server-data). This is the only place the server scans for resources.
server-data/
server.cfg
resources/
[standalone]/
[framework]/
[scripts]/
my_script/
fxmanifest.lua
client.lua
server.lua
Folders wrapped in square brackets like [scripts] are categories. A category is just an organizational bucket. The server recurses into bracketed folders to discover the resources inside them, so a resource inside [scripts]/my_script is found without any extra config. You can place one category inside another (for example [scripts]/[jobs]/my_job), but never put a fxmanifest.lua directly inside a bracketed folder. Brackets hold resources; they are not resources themselves.
The practical rule: keep your framework in [framework], shared libraries in [standalone] or [ox], and gameplay scripts in [scripts]. This keeps the load order readable later.
fxmanifest.lua: the file that defines the resource
Every resource needs a manifest. Modern servers use fxmanifest.lua (the older __resource.lua is deprecated). The manifest declares what the script is and which files to load:
fx_version 'cerulean'
game 'gta5'
author 'Quasar'
description 'Example resource'
version '1.0.0'
shared_scripts {
'@ox_lib/init.lua',
'config.lua'
}
client_scripts {
'client/*.lua'
}
server_scripts {
'@oxmysql/lib/MySQL.lua',
'server/*.lua'
}
dependencies {
'ox_lib',
'oxmysql'
}
Two lines here do real work. The @resource/file.lua syntax pulls a file from another resource, which is how scripts hook into oxmysql and ox_lib. The dependencies block tells the server that those resources must be started for this one to run. If you edit a manifest, you must restart the resource for changes to take effect.
ensure vs start vs stop
You tell the server which resources to run inside server.cfg, line by line. There are three commands you will use:
start resource_namestarts a resource once.ensure resource_namestarts it, and if it is already running, restarts it cleanly.ensureis idempotent and safe to leave in your config.stop resource_namestops it.
Use ensure for everything in server.cfg. It behaves like start on a fresh boot but also lets you reload a single resource at runtime without a full server restart. From the live server console you can also type ensure my_script, restart my_script, or refresh (which rescans the resources folder so newly added resources become known before you start them).
The order of these lines in server.cfg is the load order. That is the part people get wrong.
Dependency order: the rule that fixes most failures
FiveM starts resources roughly in the order it reads them, and a resource that depends on another will fail if its dependency has not started yet. There is a reliable order that works for almost every modern script:
- oxmysql first. It is the database connector. Anything that touches MySQL needs it already running.
- ox_lib next. It is a shared library many scripts use for menus, notifications, callbacks, and caching.
- Your framework (ESX as
es_extended, or QBCore asqb-core). Frameworks expose the player object, jobs, and money that gameplay scripts depend on. - Framework-dependent scripts last. Anything that calls
ESXorQBCoremust start after the framework.
In practice your server.cfg reads top to bottom like this:
ensure oxmysql
ensure ox_lib
ensure es_extended
ensure my_job_script
If you put ensure my_job_script above ensure es_extended, the script boots, looks for the framework, finds nothing, and errors out. The fix is almost never editing code; it is moving one line.
SQL imports: do this before the first start
Many scripts store data (vehicles, inventories, properties) in MySQL. They ship a .sql file, usually in the resource root or a sql subfolder. The server will not import this for you. If the tables do not exist when the script first runs, you get errors like Table 'database.xyz' doesn't exist.
Import the SQL into the same database your mysql_connection_string convar points at, using HeidiSQL, phpMyAdmin, or the MySQL CLI:
mysql -u root -p your_database < my_script/install.sql
Do this before you ensure the script the first time. If a script's README mentions specific columns being added to the users or players table, run those ALTER statements too.
Escrow and keymaster assets
Many paid resources are protected by FiveM's asset escrow system. The code is encrypted and tied to your server's license key, which you generate on the Cfx.re keymaster portal and set in server.cfg as sv_licenseKey. Before an escrow-protected asset will run, you must authorize it to that key, usually by linking the asset in keymaster (for Tebex/Cfx purchases) or by entering the server key in the seller's portal.
Two things matter here. First, escrow encrypts the resource's core logic while leaving the manifest and any files the seller chose to expose (often config.lua) open to edit, so do not expect to edit the protected code. Second, if escrow authorization is missing you will see a clear console message telling you the asset is not entitled to this server. The fix is authorization, not reinstalling.
A clean install, start to finish
Put it together and a correct install looks like this: download the resource, unzip it, rename the folder to remove version numbers or -main suffixes, drop it into the right category in resources, import any SQL, add ensure lines to server.cfg in dependency order, authorize escrow if needed, then run refresh and ensure from the console or restart the server. Watch the console on first boot; it tells you exactly what failed and why.