Organize your server folders
Most broken servers are not broken by bad code. They are broken by mess: a resource that loads before the library it needs, a script dropped in the wrong folder, a server.cfg nobody can read. In this lesson you build the layout that prevents all three. By the end you will know where every file belongs and why, and you will start an entire category of resources with a single line.
The two folders that are not the same
Before you touch anything, lock in the single most important split in a FiveM server. There are two top-level folders and they do completely different jobs.
C:\FXServer\
├── server/ # the ARTIFACTS: FXServer.exe / run.sh, the engine. Update freely.
└── server-data/ # YOUR content: resources/ + server.cfg. This is what you back up.The server/ folder holds the artifacts: the FiveM server binaries you downloaded from the artifacts page. Think of it as the engine. You replace its contents every time you update the server, and you never edit anything inside it by hand.
The server-data/ folder holds your content: the resources/ folder full of scripts, and the server.cfg that decides what runs. This is the folder you version-control and back up. They are kept separate on purpose, so updating the engine never risks your scripts, and backing up your scripts never drags along a few hundred megabytes of binaries.
The server is launched from inside server-data/, pointing back at the engine and handing it your config:
# Windows, run from inside server-data:
C:\FXServer\server\FXServer.exe +exec server.cfg
# Linux, run from inside server-data:
bash ~/FXServer/server/run.sh +exec server.cfgThat +exec server.cfg is the whole handoff. The engine starts, reads your server.cfg top to bottom, and that file is what you spend the rest of this lesson organizing.
Build it
Open server-data and find resources
Open your server-data/ folder in VS Code. You should see exactly two things at the root: the resources/ folder and your server.cfg file.
server-data/
├── resources/
└── server.cfgThe server.cfg lives at the root of server-data/, right next to resources/, not inside it. Everything you build next happens inside resources/.
Create the four category folders
Inside resources/, create four folders whose names are wrapped in square brackets:
resources/
├── [framework]/ # the framework + its hard dependencies
├── [standalone]/ # shared deps that any script can use
├── [scripts]/ # your gameplay scripts
└── [maps]/ # MLOs, map streams, YMAPsA folder whose name is wrapped in [brackets] is special. FiveM treats it as a category group, not a resource. The brackets are part of the real folder name on disk: the folder is literally called [framework], square brackets and all.
Drop resources into the right group
Now place a few real resources so the layout has shape. Note the load-sensitive trio inside [framework]: the database layer, the shared library, then the framework itself.
Here is the same server-data layout as it looks in your editor, so you can match it folder for folder:
How it works
The server booted clean and one line started a whole group. Now take the layout apart so the next time you add a resource you know exactly where it goes and why the order matters.
Artifacts vs data: why the split exists
The reason server/ and server-data/ are separate folders comes down to one word: updates. The artifacts in server/ change constantly. The FiveM team ships new server builds often, and updating is supposed to be as simple as deleting the contents of server/ and dropping in the new build. If your scripts and your config lived in that same folder, every update would put your work at risk of being wiped.
By keeping your content in server-data/, the two lifecycles never touch. You update the engine without fear, because your data is somewhere else entirely. You back up your data without bloat, because the binaries are somewhere else entirely. This is also why server-data/ is the folder you put under version control with Git: it is the part that is actually yours.
What a [bracket] folder really is
A folder named [scripts] is not a resource. FiveM never tries to start it as a script, because it has no fxmanifest.lua of its own. Instead, when the server scans resources/, it sees the brackets and treats that folder as a container: a labelled box whose only job is to hold other resources.
That single fact is what makes ensure [scripts] work. You are not starting a resource called [scripts]. You are telling the server, start every resource you can find inside this box. The server walks into the folder, finds each real resource by its fxmanifest.lua, and starts them all. One line, the whole group.
The names are a community convention, not a fixed list. [framework], [standalone], [scripts], and [maps] are the common ones, but the server does not care what the brackets say. You could make [jobs] or [economy] tomorrow. What matters is only that the name is wrapped in brackets, which flips the folder from "resource" to "category group".
You drop a brand-new script folder inside [scripts] while the server is running and then type ensure [scripts], but it does not start. Why?
Because the server has not noticed the new folder yet. The resource list is built when the server scans resources/, and a folder added while the server is live is not in that scan. Run refresh first: it rescans resources/ and loads the new manifest. Then ensure [scripts] will find the new resource and start it. The fix is always the same pair when adding resources live: refresh, then ensure.
Why folder order becomes load order
This is the part that bites everyone once. Resources do not load in alphabetical order, and they do not load all at the same instant. They load in the order their ensure lines appear in server.cfg, top to bottom. Whichever line is higher in the file loads first.
That ordering is not cosmetic. Many resources depend on others being ready first. A framework like es_extended calls into the database layer the moment it starts, so oxmysql has to already be running. The same framework reads from the shared library ox_lib, so that has to be running too. Get the order right and everything finds what it needs:
# CORRECT: dependency first, dependent second
ensure oxmysql # registers the database exports
ensure es_extended # calls those exports on start -> they exist -> OKGet it backwards and the dependent resource reaches for exports that do not exist yet, and it errors out during boot:
# WRONG: dependent before dependency -> startup error
ensure es_extended # tries to use oxmysql exports that are not registered yet -> error
ensure oxmysqlThe reliable order is always the same: database layer, then shared library, then framework, then the scripts that build on the framework, then maps. That is exactly why the [framework] folder groups oxmysql, ox_lib, and es_extended together, and why those three ensure lines sit at the top of your config in that sequence.
If everything in [framework] needs to load before everything in [scripts], can you just ensure both bracket folders and trust the order?
Mostly, but with a sharp edge. Ordering between groups is reliable: ensure [framework] above ensure [scripts] does load the whole framework group before the scripts group. What brackets do NOT give you is fine-grained order inside a group. ensure [framework] starts oxmysql, ox_lib, and es_extended, but does not promise es_extended loads last. When the order within a group matters, list those few resources by name in the exact sequence you need, instead of relying on the bracket. Brackets group; they do not sort.
When you reach for this layout
This structure is not academic tidiness. It saves you real time the moment a server has more than a handful of resources:
- Adding a script. You downloaded a new job script. It drops into
[scripts], yourefreshandensure [scripts], and you are done. No hunting for where it belongs and no newensureline. - Updating a dependency. A new
ox_librelease comes out. You know exactly where the old one lives, inside[framework], because every shared dependency lives there. Swap the folder, restart, done. - Handing the server to someone else. A teammate opens
server-data/and instantly reads the shape of the server from the folder names alone. The structure is the documentation.
Common mistakes
| Symptom | Fix |
|---|---|
es_extended errors on boot: attempt to call a nil value (oxmysql export) | Load order is wrong. The framework loaded before its database layer. Move ensure oxmysql (and ensure ox_lib) ABOVE ensure es_extended in server.cfg. Dependency first, dependent second. |
ensure [scripts] does nothing after you add a new folder while the server is live | The server has not rescanned the resources folder. Run refresh first, then ensure [scripts]. A folder added during a live session is not in the resource list until a refresh. |
Couldn't find resource [scripts] | The brackets are wrong or missing on disk. The folder must literally be named [scripts] with square brackets. A folder named scripts with no brackets is treated as a normal resource, not a category group. |
A resource you put inside a bracket folder never starts | It is missing its fxmanifest.lua, or it is nested one level too deep. A bracket folder holds resource folders directly; each resource needs its own fxmanifest.lua for the server to recognize and start it. |
Your edits to a script keep getting wiped on update | You are editing inside the server/ artifacts folder. Scripts belong in server-data/resources/, never in server/. The artifacts folder gets replaced on every update. |
What you can do now
- Explain the split between the server/ artifacts folder and the server-data/ content folder, and why updates and backups stay clean because of it.
- Create bracketed category folders like [framework], [standalone], [scripts], and [maps], knowing the brackets are part of the real folder name.
- Start every resource inside a bracket folder with a single ensure line, after a refresh when the folder is new.
- Order ensure lines so dependencies load before dependents: database layer, shared library, framework, scripts, maps.
- Diagnose a nil-export startup error as a load-order problem and fix it by moving the dependency higher in server.cfg.