server.cfg, annotated line by line
The conceptual lesson taught you that server.cfg is read top to bottom and that order is a rule. This is the worked-example companion: one complete config you build line by line, then take apart section by section. By the end you will be able to open any server's config, point at a line, and say exactly what it does and what breaks if it is wrong.
Where the file lives
server.cfg is not a resource. It is the startup script for the whole server, and it lives at the root of your server-data folder, right next to the resources folder. The server is launched by pointing the artifacts at it with +exec server.cfg.
C:\FXServer\
├── server/ # FXServer artifacts (FXServer.exe / run.sh) — update freely
└── server-data/ # YOUR content — this is what you version-control
├── resources/
│ ├── [framework]/ # community convention: a [bracketed] folder is a group
│ │ ├── oxmysql/
│ │ ├── es_extended/ # or qb-core / qbx_core
│ │ └── ox_lib/
│ ├── [standalone]/ # standalone deps: ox_target, ox_inventory, etc.
│ └── [scripts]/ # your own gameplay scripts
└── server.cfg # <- you are editing THIS, at the root of server-dataTwo things to lock in before you write a line. First, the artifacts (server/) and your data (server-data/) are kept in separate folders on purpose, so you can update the binaries without touching your content. Second, the [brackets] around [framework] and [scripts] are a community convention, not a FiveM feature you must use. A folder whose name is wrapped in brackets is treated as a grouping container, so you can keep things tidy, but the brackets only group resources. They do not control load order. Load order still comes from the order of your ensure lines, which you are about to write.
Build it
Open server.cfg at the root of server-data
Open server-data/server.cfg in your editor. If it has starter content from a txAdmin recipe, you can read along, but for this lesson you are going to write the file in full so every line is yours. Clear it or start a fresh server.cfg you can compare against.
Write the complete file, top to bottom
Paste this entire file. Every line is explained in the next section. The order of the sections is deliberate: built-in resources and dependencies load first, identity and tuning sit in the middle, and the required license key anchors the bottom.
## ============================================================
## server.cfg — annotated starter (2026)
## ============================================================
## --- Endpoints (how players reach the box) ---
# 0.0.0.0 = all network interfaces. Only change the IP on a multi-NIC box.
# 30120 is the canonical FiveM port. Change the PORT, not the IP, if you must.
endpoint_add_tcp "0.0.0.0:30120"
endpoint_add_udp "0.0.0.0:30120"
## --- Resource start order (top to bottom = load order) ---
# Built-in resources first.
ensure mapmanager
ensure chat
ensure spawnmanager
ensure sessionmanager
ensure basic-gamemode
ensure hardcap
ensure rconlog
# Then dependencies BEFORE the resources that depend on them:
ensure oxmysql # database layer (registers MySQL exports)
ensure ox_lib # shared library (callbacks, UI, utils)
How it works
You booted it and it came up. Now take the file apart section by section so the next time you read someone else's config you are deciding, not guessing. The file is grouped on purpose. Read it as endpoints, then start order, then identity and tuning, then permissions, then the license key.
Endpoints: how players reach the box
endpoint_add_tcp "0.0.0.0:30120"
endpoint_add_udp "0.0.0.0:30120"These two lines bind the network address the server listens on. FiveM needs both TCP and UDP on the same port. The 0.0.0.0 part means all network interfaces on the machine, which is the correct value for almost every host. The number after the colon is the port, and 30120 is the canonical FiveM port that the launcher and server browser expect.
The single most common mistake here is editing the IP when you should not. People hardcode their machine's LAN address into 0.0.0.0, the binding breaks, and nobody can connect. Leave the IP as 0.0.0.0. Only change it if the box genuinely has multiple network cards and you need to pin one. If you must move off the default port, change the number, not the IP.
Resource start order: the order is the order
ensure oxmysql # database layer
ensure ox_lib # shared library
ensure es_extended # framework, depends on oxmysql + ox_lib
ensure my_job_script # your script, depends on es_extendedThis is the section the conceptual lesson hammered, and it is the one that bites beginners most. FXServer reads server.cfg from top to bottom, and that reading order is the load order. There is no separate priority field. A resource that needs another resource's exports or events must be ensured below the one it depends on, because the dependency has to be running before the dependent tries to call it.
The chain in this file is the standard one. oxmysql first, because it registers the database exports everything else uses. Then ox_lib, the shared utility library. Then your framework, es_extended here (it would be qb-core or qbx_core on a Qbox server), which calls into both of those on startup. Then your own scripts, which call into the framework. Flip any two of these and the higher one errors on boot with a missing export or event, because the thing it needs has not started yet.
Notice the directive is ensure, not start. ensure is idempotent: it starts the resource if it is stopped and restarts it if it is already running. start errors if the resource is already up and is useless on a live restart. Always reach for ensure in the config. And if you drop a brand-new resource folder in while the server is live, run refresh in the console first so FXServer rescans and loads its manifest, then ensure it.
You add ensure my_job_script ABOVE ensure es_extended by mistake. What happens at boot, and why?
my_job_script errors on startup, usually with a missing-export or unknown-event message, because it tries to call into es_extended before that framework has started. Load order is literally the top-to-bottom order of the ensure lines, so a dependent listed above its dependency runs first and the thing it needs does not exist yet. The fix is to move the dependent line below every resource it relies on: database layer, then shared library, then framework, then your script. The brackets on folders like [scripts] do not save you here; they group resources but do not reorder them.
Identity and the set / sets / setr distinction
sv_hostname "Quasar Academy RP"
sets sv_projectName "Quasar Academy"
sets sv_projectDesc "A teaching server built from zero."
sets tags "roleplay, jobs, economy"
sets locale "en-US"This block is where the prefix matters more than the value. FiveM has three convar prefixes and using the wrong one means your value silently does not reach where you expect.
setis a plain server-side convar. Nobody outside the server sees it. Use it foronesync,maxclients, and internal settings.setsis a server-info convar. It replicates to the server browser and to connecting clients. Anything that should show in the public listing, the project name, the description, the tags, the locale, the banners, must usesets. Use plainsetfor these and they will not appear in the browser.setris a replicated convar that scripts can read on the client at runtime. Thesetr server_motd "Welcome to the city."line in this file is an example: a value you set in config and read from Lua on the client.
sv_hostname is the name shown in-game and is a plain set-style line of its own. The starter ships sets locale "root-AQ" as a placeholder and the docs explicitly tell you to replace it with a real locale like en-US, fr-CA, or pt-BR. If you leave the placeholder, your server advertises a nonsense language.
Slots, OneSync, and game build
set onesync on
sv_maxclients 48
sv_enforceGameBuild 3407sv_maxclients is your slot count and accepts 1 to 2048, though your practical ceiling depends on your OneSync tier and your hosting. The starter uses 48.
set onesync on is the line that gets written wrong in old tutorials. The current syntax is set onesync on. The old onesync_enabled true form is deprecated and you should not copy it. OneSync has three values: on for full state awareness, which you need for server-side entity logic and for routing buckets; legacy for a compatibility mode; and off for plain peer-to-peer. The slot rule is specific: 32 to 64 slots require OneSync set to on or legacy, and above 64 slots strictly requires on. For a real server in 2026 you want on.
sv_enforceGameBuild locks which GTA5 build clients load, so everyone is on the same game version as your content. The critical property of this convar is that it is startup-only. You cannot change it while the server runs; you set it here and restart. Pick a current build. As of 2026 the values you care about are 3258 (Bottom Dollar Bounties), 3407 (Agents of Sabotage), 3570 (Money Fronts), and 3751 (A Safehouse in the Hills). This file uses 3407. Do not paste an outdated 2802 from a years-old guide unless your content specifically needs it.
Permissions: the ACE tree
add_ace group.admin command allow # group.admin may run all commands
add_ace group.admin command.quit deny # except quit
add_principal identifier.fivem:1 group.admin # put a player in the groupFiveM permissions are an ACE tree. You build it with two directives. add_ace [principal] [object] [allow|deny] grants or denies a principal access to an object, which is usually a command. add_principal [child] [parent] makes one principal inherit another, which is how you put a real player into a group.
Read the three lines as a story. The first gives the group.admin principal the right to run every command. The second carves out an exception: group.admin may run everything except quit, so an admin cannot accidentally shut the whole server down with a typo. The third line is the one you personalize: it puts a specific player, identified by identifier.fivem:1, into group.admin, so that player inherits the admin rights you just defined.
The identifier is the part you change. Players can be identified by identifier.fivem:, identifier.steam:, identifier.license:, or identifier.discord:. You get the real value by running status in the live console, which prints every connected player with their identifiers. Frameworks layer their own naming on top of this same ACE system: ESX uses group.admin and group.owner, QBCore uses qbcore.god and qbcore.admin, and Qbox uses group.admin, group.mod, and group.support. They are all just principals in this same tree.
You ran /addpermission or added a principal in the live console and it worked, but after a restart the admin is gone. Why?
Permissions added at runtime in the console are session-only ACE principals. They apply to the current run of the server and are not written back to server.cfg. When the server restarts it re-reads the config, and since your live grant was never saved there, the admin loses access. For a permanent admin you must add the matching add_principal identifier.<type>:<id> group.admin line to server.cfg (or to a permissions.cfg you exec). Runtime grants are for quick testing; the config file is the source of truth that survives a restart.
The license key: the line that decides if it boots
sv_licenseKey changemeThis is the one required line. Without a valid key the server refuses to start. The starter ships the literal placeholder changeme, and leaving it is the number one reason a fresh server will not boot. Get your key from the Cfx.re portal at https://portal.cfx.re. The old keymaster.fivem.net URL still redirects, but portal.cfx.re is the current home.
It sits at the bottom of this file by convention, but FiveM does not care where it appears. What matters is that it is present and valid. Because it is a secret, many owners move it out of the main server.cfg into a separate file they exec and keep out of version control, so the config can be shared without leaking the key.
Common mistakes
| Symptom | Fix |
|---|---|
Server refuses to start, console mentions the license key | You left sv_licenseKey changeme as the placeholder, or pasted an invalid key. Get a fresh key from portal.cfx.re and paste the exact value with no quotes or trailing spaces. |
Your server name and tags never appear in the server browser | You used set instead of sets for sv_projectName, sv_projectDesc, tags, or locale. Server-info convars must use sets so they replicate to the list. Use plain set only for onesync and maxclients. |
A framework or script errors on boot with a missing export or unknown event | A dependent resource is ensured above its dependency. Move it below: ensure oxmysql, then ox_lib, then the framework, then your script. Load order is the top-to-bottom order of the lines. |
onesync_enabled true does nothing or warns it is deprecated | That is the old syntax. Use set onesync on. OneSync must be on for server-side state awareness and routing buckets; 32 to 64 slots require on or legacy, and above 64 slots requires on. |
Nobody can connect after you edited the endpoints | You changed the 0.0.0.0 IP. Put it back. 0.0.0.0 binds all interfaces and is correct for almost every host. Change only the port number, never the IP, unless the box has multiple network cards. |
sv_enforceGameBuild change is ignored until you restart | That convar is startup-only and cannot change at runtime. Set it in server.cfg, then fully restart the server. Pick a current build like 3407 or 3751, not an outdated one. |
Your admin works until the next restart, then loses access | You granted the principal in the live console, which is session-only. Add the add_principal line to server.cfg so it survives a restart. |
What you can do now
- Place server.cfg at the root of server-data and launch the server with +exec server.cfg.
- Read the endpoints block and know to change the port, never the 0.0.0.0 IP.
- Order the ensure block so every dependency loads above the resources that need it, and use ensure over start.
- Choose set, sets, or setr correctly: sets for anything in the server browser, setr for client-readable convars, set for everything else.
- Turn OneSync on with the current set onesync on syntax and pick a valid, current sv_enforceGameBuild.
- Build the ACE permission tree with add_ace and add_principal, and know that runtime grants must be written to the config to survive a restart.
- Recognize sv_licenseKey as the one required line, get it from portal.cfx.re, and keep it secret.