There is a specific moment in every FiveM server's life where it works on Tuesday and does not start on Wednesday, and nothing in the resource changed. The cause is almost always this: server.cfg and resources.cfg are two different files with two different jobs, and the order in which FiveM reads them decides what actually starts.
Let me clear up what each file does, then walk through the failure patterns I see most often.
What server.cfg actually does
server.cfg is the file you pass to the server binary. It is not a resource list, even though it often ends up containing one. Its job is to set the runtime configuration for the instance: your server name, the license key, the set and sets directives, the networking ports, and one or two exec calls.
A minimal server.cfg looks like this:
endpoint_add_tcp "0.0.0.0:30120"
set sv_projectName "My Server"
set sv_maxclients 48
set mysql_connection_string "mysql://user:pass@127.0.0.1:3306/mydb"
sets locale "de"
exec server.cfg
That last line is the part that matters for the rest of this article.
What resources.cfg actually does
resources.cfg is a resource list. It contains ensure directives and nothing else that belongs in a config file. Its job is to say which resources start, and in which order.
ensure mapmanager
ensure sessionmanager
ensure qb-core
ensure qb-policejob
ensure my-custom-script
This file is loaded by exec from server.cfg, or by exec from another exec'd file. The usual convention is a single exec server.cfg in the launch config, and that file does exec resources.cfg.
The order of operations, precisely
This is the part that causes confusion, so here is the sequence in full:
- The server binary starts and reads the config you passed on the command line, usually
+exec server.cfg. - Every
setandsetsdirective in that file is applied immediately. -
execdirectives are processed. Each exec'd file is read and processed in turn. - Resources named with
ensureare queued. - After the entire config tree has been read, the queued resources start, in the order they were queued.
Step 5 is the important one. Resources do not start as soon as their ensure line is read. They start after all configuration is done. Which means this is legal and does what you expect:
exec resources.cfg
And this is also legal, and does something completely different:
ensure qb-core
ensure my-custom-script
exec resources.cfg
Here the two ensure lines are queued before the exec, so they end up ahead of everything in resources.cfg. The ensure order that determines the startup order is the order of the queue, not the order of the file sections.
Failure pattern 1: the double exec
The single most common mistake I see is exec resources.cfg appearing twice, or appearing in both server.cfg and the command line.
# server.cfg
exec resources.cfg
# start command
+exec server.cfg +exec resources.cfg
Every resource gets queued twice. On the first pass resources start and register their exports. On the second pass the server tries to start them again, and depending on the resource you get one of three outcomes: a clean no-op, a console error about the resource already being started, or a genuine failure where the second start tries to re-create something that already exists.
If your server logs show resources starting twice, or a resource that works fine but whose events fire twice, this is the cause. Check the launch command first, then the config file.
Failure pattern 2: the config that never got loaded
The reverse problem. A resource reads a value from cfg that was supposed to be set in server.cfg:
local apiKey = GetConvar("rpscripts_api_key", "")
If server.cfg is missing the set rpscripts_api_key "..." line, the resource starts with an empty string and quietly does nothing. No error, no crash, just a feature that never activates.
The confusing part is that this often only shows up after a restart, because the developer had the value set in a local config that never made it to production. It also only shows up on the server that has the missing line, which is why it is hard to reproduce.
Two habits prevent this. First, keep every set directive in exactly one file, never spread across the launch command and the config. Second, after editing a config, check the effective values rather than the file: the server console exposes the running configuration, and a set you cannot find there is not set.
Failure pattern 3: ordering across framework and content
Within resources.cfg, order is dependency order. Frameworks first, then the libraries that sit on the framework, then your content.
ensure mapmanager
ensure sessionmanager
ensure qb-core
ensure qb-multicharacter
ensure qb-policejob
ensure qb-inventory
Get this wrong and you get the classic symptom: a resource that depends on qb-core starting before qb-core exists. It then fails to find the framework object, throws during initialization, and the server moves on without it. The resource is not in the dependency graph at all, so it never restarts by itself.
The robust fix is to declare dependencies in the resource manifest rather than relying purely on the ensure order:
fx_version 'cerulean'
game 'gta5'
description 'My custom script'
version '1.0.0'
dependency 'qb-core'
With dependency declared, the server starts the dependency first regardless of the order of the ensure lines. You keep the file readable for humans, and you get correctness from the manifest. Relying on file order alone works right up until someone reorders the file for tidiness.
Failure pattern 4: the resource that stops the line
One resource throwing during its own initialization can prevent later resources from starting. This is worth knowing because it makes a single broken script look like a whole server problem.
The symptom is a server that starts, prints the first handful of resources, and then goes quiet. You check each resource individually and they all work. The actual fault is usually a resource whose fxmanifest.lua has a syntax error, or which tries to read a database table that does not exist yet. That resource fails, and depending on how the failing resource handles its own error, the resources queued behind it never get their start.
A quick way to bisect this: start the server with only the framework, then add resources back in groups. The resource where the log stops is the one to fix.
A practical validation order
Before you trust a config, check it in this order:
- Does
server.cfgcontain exactly oneexecof the resource list, and does the launch command not also exec it? - Are all
setvalues present in the file that is actually being read? - Does every resource that needs a framework declare it as a
dependencyin its manifest? - Do the
ensurelines follow a sane order anyway, so the file reads correctly to a human? - Does the startup log show every resource you expect, exactly once, in a sensible order?
For step 5, and for the checks in step 2, the console is the source of truth, not the file on disk. A server that is currently running has a resolved configuration, and reading that is more reliable than reading your intent.
Where this bites hardest
None of this is exotic. It is the daily mechanics of running a FiveM server, and it is the reason so many "my script is broken" reports turn out to be a config problem rather than a code problem. The free script archive on RPScripts keeps known-good fxmanifest.lua files around for exactly this kind of comparison, and if you are validating a resource before you ship it, the script tester runs your manifest and Lua through the checks that catch most of the above.
If your server.cfg is more than a handful of lines, it is worth having it validated mechanically rather than by reading, because the failure modes above are all invisible in a diff. The server.cfg builder and checker parses the file, verifies that every exec target exists, and flags the duplicate-exec case before it costs you a restart. Once the config is clean, the next thing worth automating is the resource itself: a manifest validator and a Lua checker catch the errors that would otherwise show up as a broken server at 2 AM.
If you have hit the "works Tuesday, broken Wednesday" case, look at the exec structure first. It is the cause more often than not, and it is the fastest thing to check.
Top comments (0)