Skip to main content
TRACK A·INSTALL YOUR SERVER·Verified June 2026 · Lua 5.4 · ox_lib 3.x
Learning with an AI assistant?
Copies this lesson plus 2026 ground rules (no lua54 'yes', Cfx.re Portal, correct callback signatures) as a ready-to-paste mentor prompt.
Step 04

Configure server.cfg: complete annotated guide

server.cfg is the startup script for your city. It names the server, sets the port, holds your secrets, and decides the order every resource loads. FXServer reads it top to bottom, and that reading order is the load order. There is no separate priority field. In this lesson you build one complete config line by line, take it apart section by section, and inspect a real manifest so you can place any script correctly without touching a single production script.

You'll do
Write one complete, production-shaped server.cfg top to bottom: endpoints, resource load order, identity, OneSync, game build, ACE permissions, and the license key - then read a real script's manifest to place it correctly.
Time
~30 minutes.
You need
Step 03 done: a running server you can reach in txAdmin, your server folder open in a text editor, and a Cfx.re license key from portal.cfx.re (or you know to get one there).
Result
You can write, defend, and troubleshoot every line of a real server.cfg, explain why load order matters, and place any script correctly by reading its manifest.
BEFORE YOU START

The Live Console and the CFG Editor are pages in the txAdmin sidebar at localhost:40120. You get the full tour in the next lesson; this lesson only opens those two pages.

Where the file lives

server.cfg is not a resource. It is the startup script for the whole server. It lives at the root of your server-data folder, right next to the resources folder. You launch the server by pointing the artifacts at it with +exec server.cfg, or txAdmin does this for you if it manages the server.

For the full folder layout, see Organize your server folders. Short version: server/ holds the artifacts, the FXServer build you downloaded, and you update it freely. server-data/ holds your config and resources, and you version-control it.

Build it

Open server.cfg and back it up

You are editing the one file FXServer runs at startup, with a safe fallback copy.

Open your server folder in VS Code (right-click the folder, Open with Code), then open server-data/server.cfg. If a txAdmin recipe already wrote starter content, you can read along, but in this lesson you write the file in full so every line is yours.

Before you clear anything, copy server.cfg to server.cfg.bak first (right-click the file, Copy, then Paste, and rename the copy), so you can always fall back to the recipe's version. Then clear the file, or start a fresh server.cfg you can compare against.

A recipe is the one-click starter txAdmin runs to download a framework and write your first config.

Write the complete file, top to bottom

You have a full, bootable, 2026-correct server.cfg.

Paste this entire file. Every line is explained in the How it works section below. The order of the sections is deliberate: the base resources from cfx-server-data and your dependencies load first, identity and tuning sit in the middle, and the required license key sits at the bottom.

cfg
## ============================================================
## 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) ---
# Base resources from cfx-server-data first (recipes include them for you).
ensure mapmanager
ensure chat
ensure spawnmanager
ensure sessionmanager
ensure hardcap    # enforces the slot limit
ensure rconlog    # logs remote console (RCON) activity
 
# Add only resources that actually exist in your resources folder.
# Follow the official recipe and each manifest: dependency before dependent.
# ensure oxmysql
# ensure ox_lib
# ensure es_extended
# ensure my_job_script
 
## --- ScriptHook (0 = blocked, the safe default) ---
sv_scriptHookAllowed 0
 
## --- RCON (leave commented to keep it disabled) ---
#set rcon_password "CHANGE_ME_TO_SOMETHING_STRONG"
 
## --- Server browser info (sets = replicated to the server list) ---
sets tags "roleplay, jobs, economy"
sets locale "en-US" # replace root-AQ from the starter with a REAL locale
#sets banner_detail "https://url.to/your-banner.png"
#sets banner_connecting "https://url.to/your-connect-banner.png"
 
sv_hostname "Quasar Academy RP"
sets sv_projectName "Quasar Academy"
sets sv_projectDesc "A teaching server built from zero."
 
## --- Game build (optional — omit to serve the vanilla base game with NO DLC content, or pin a supported build for DLC) ---
# sv_enforceGameBuild <supported-build>   # uncomment for DLC content; set the build your ASSETS require, from the current Cfx.re supported list (e.g. 3751, but verify against the current list)
 
## --- Icon / nested configs ---
#load_server_icon myLogo.png # 96x96 PNG next to server.cfg
#exec permissions.cfg # split admins into their own file if you like
 
## --- Replicated convar a script can read at runtime ---
setr server_motd "Welcome to the city."
 
## --- Admins (FiveM ACE permission tree) ---
add_ace group.admin command allow # the admin group may run all commands
add_ace group.admin command.quit deny # except quit, so a typo can't kill the box
add_principal identifier.fivem:1 group.admin # put a real player in the admin group
 
## --- OneSync (not on by default — set it; required for >31 slots) ---
set onesync on
 
## --- Slots ---
sv_maxclients 48
 
## --- Steam auth (optional) ---
set steam_webApiKey ""
 
## --- License key (REQUIRED — the server will not boot without it) ---
# Get yours at https://portal.cfx.re
sv_licenseKey "changeme"

Replace the two values that must be yours

The file is no longer a template; it is your server.

Two lines ship as placeholders. The server will not run correctly until you change them. The How it works section below explains what each one does and why it matters.

cfg
sv_licenseKey "changeme"
add_principal identifier.fivem:1 group.admin

Replace changeme with the real key from https://portal.cfx.re. The key is a single cfxk_ string. Paste it verbatim, with no licensekey: prefix, so the line reads sv_licenseKey "cfxk_yourkeyhere". FXServer accepts the key with or without quotes; this course always quotes it for consistency.

Replace identifier.fivem:1 with your own identifier. An identifier is the unique ID FiveM ties to a player, such as their Cfx.re, Steam, license, or Discord ID. To find yours, join the server and open your player record in txAdmin's Players panel, then copy the full fivem: value. The status command shows a player's primary identifier only, not every type.

Boot the server and read the console

The server starts clean and lands on your config.

If txAdmin manages this server, which is the path this course uses, edit the config in txAdmin's CFG Editor and click Restart to apply it. The commands below are the vanilla, non-txAdmin launch path for a server you boot by hand. Launching FXServer with +exec directly bypasses the normal txAdmin startup and can create a second server process, so only use it if txAdmin is not managing this server.

text
# Windows, run from server-data:
C:\FXServer\server\FXServer.exe +exec server.cfg
 
# Linux, run from server-data:
bash ~/FXServer/server/run.sh +exec server.cfg

Watch the console run the file top to bottom. Each ensure line starts its resource in order, then the server settles and reports it is listening. ensure is the directive that starts a resource (and restarts it if it is already running).

The exact lines depend on your resources. The shape is the goal: resources start in the order you wrote them, and the license key authenticates instead of refusing to boot.

Read the ensure block as a dependency map

You can say why each line sits where it does.

Order is not random. Read it as layers. Each one depends on the layer above:

text
# 1. Database bridge first, anything that saves data needs it
ensure oxmysql
 
# 2. Shared helper library second
ensure ox_lib
 
# 3. Framework core third
ensure es_extended
 
# 4. Core gameplay systems after the framework
ensure ox_inventory
ensure ox_target
 
# 5. Your scripts last, after everything they depend on
ensure qs-smartphone-pro

A script that calls lib. functions needs ox_lib above it. The lib table does not exist until ox_lib loads and the script pulls it in (Step 6 shows exactly how, by reading the manifest). A script that saves to the database needs oxmysql above it. A job script needs its framework above it. Get one wrong and the script errors at startup, not when you expect it.

First, one word you need. An export is a function one resource publishes so other resources can call it. It is the FiveM way resources talk to each other. A resource can only answer an export call after it has started.

Here is the same idea reduced to its smallest form, so you can see exactly what flips. es_extended calls oxmysql exports the moment it starts. Put the database layer first and those exports already exist. Put the framework first and it reaches for exports that have not been registered yet:

cfg
# CORRECT: dependency first, dependent second
ensure oxmysql # registers the MySQL exports
ensure es_extended # calls exports.oxmysql:* on start -> they exist, boots clean
 
# WRONG: dependent before dependency -> startup error
ensure es_extended # tries to use oxmysql exports that do not exist yet -> errors
ensure oxmysql # too late, the framework already failed above

The fix is never "restart it again" or "ensure it twice." The fix is to move the dependency line above the line that needs it, save, and reload. Order is the whole mechanism.

Here is an example chain for a script whose own README and manifest name all three dependencies. Do not assume every framework needs every ox resource. Install only what the official recipe and the resource manifest require.

cfg
ensure oxmysql # database bridge, registers MySQL exports first
ensure ox_lib # shared library, defines the global lib used by the rest
ensure es_extended # framework; its recipe requires oxmysql
ensure qs-smartphone-pro # example only: place it after every dependency its docs name

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 only acts on a stopped resource; run it against one that is already up and it does nothing (the console just notes the resource is already started), so it will not pick up your changes on a live restart. Always reach for ensure in the config. If you drop a brand-new resource folder in while the server is live, run refresh in the console first so FXServer rescans and reads its manifest, then ensure it.

oxmysql is the modern database wrapper; the older mysql-async and ghmattimysql wrappers are deprecated. A framework like ESX (es_extended), QBCore (qb-core), or Qbox (qbx_core, the modern ox-based fork) starts after its own dependencies, and your own scripts come last.

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 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 wrapper, then shared library, then framework, then your script. Bracket folders like [scripts] group resources but do not reorder them.

Check a real script's dependencies before you install it

You can predict the right ensure position without restarting anything live.

For real paid scripts, inspect, do not restart. Open the resource's fxmanifest.lua and read its dependencies block and any shared scripts it pulls in:

lua
fx_version 'cerulean'
game 'gta5'
 
shared_script '@ox_lib/init.lua'
 
dependencies {
'ox_lib',
'oxmysql',
'es_extended'
}

That @ox_lib/init.lua line is not a hint. It is the mechanism. The @resource/file.lua syntax tells FXServer to run another resource's file inside this one before its own scripts. So shared_script '@ox_lib/init.lua' runs ox_lib's init file here, and that init is what defines the global lib table this script then calls. If ox_lib has not started yet, the @ox_lib/init.lua include has nothing to pull in, lib is nil, and the script errors the instant it touches lib.. That is the real reason ox_lib must be ensured above any script that uses it.

The dependencies block says the same thing in plain words: this script needs ox_lib, oxmysql, and the framework ensured above it. Confirm each one already sits higher in server.cfg, then add the script below them. No live restart required.

How it works

Now take the rest of the file apart section by section, so the next time you read someone else's config you are deciding, not guessing.

Endpoints: how players reach the box

cfg
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 correct for almost every host. The number after the colon is the port. 30120 is the canonical FiveM port that the launcher and server browser expect.

The 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.

Identity and the set / sets / setr distinction

cfg
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"

A convar is a configuration variable you set in the config. Here the prefix matters more than the value. FiveM has three convar prefixes, and the wrong one means your value silently does not reach where you expect.

  • set is a plain server-side convar. Nobody outside the server sees it. Use it for onesync, sv_maxclients, and internal settings.
  • sets is a server-info convar. It replicates to the server browser and to connecting clients. Anything that should show in the public listing (project name, description, tags, locale, banners) must use sets. Use plain set for these and they will not appear in the browser. Never put a secret behind sets, because sets publishes the value to the public server list.
  • setr is a replicated convar that scripts can read on the client at runtime. The setr server_motd "Welcome to the city." line is the example: a value you set in config and read from Lua on the client.

sv_hostname is the name shown in-game and uses a plain set-style line of its own. Do not change it to setr. The starter ships sets locale "root-AQ" as a placeholder, and the docs tell you to replace it with a real locale like en-US, fr-CA, or pt-BR. Leave the placeholder and your server advertises a nonsense language.

The database connection: another secret

If your resources folder includes oxmysql or a framework, uncomment its ensure line in Step 2 and add its connection convars near the top of the file, alongside the other secrets:

text
set mysql_connection_string "mysql://root:[email protected]/fivem"
set mysql_slow_query_warning 150

mysql_connection_string is how oxmysql reaches your database. mysql_slow_query_warning 150 makes the console warn you about any query slower than 150 ms.

Slots, OneSync, and game build

cfg
set onesync on
sv_maxclients 48
# sv_enforceGameBuild <supported-build>   # ships commented; uncomment when you need DLC content, set the build your assets require

sv_maxclients is your slot count. It accepts 1 to 2048, though your practical ceiling depends on your OneSync mode and your hosting. The starter uses 48, which needs onesync on (any value of 32 or higher does). Without OneSync the cap is 31.

OneSync is FiveM's server-side state synchronization system. It is not on by default; you have to add set onesync on yourself. It is the modern standard every server should set, and the value you want. Without OneSync the cap is 31 slots. onesync legacy is a compatibility mode that reaches up to 64 slots but is not recommended for a new server. onesync on is the full mode and goes all the way up to 2048 slots. It also gives you full server-side state awareness for server-side entity logic and routing buckets. Any sv_maxclients of 32 or higher requires onesync on (or legacy). The old onesync_enabled true form is deprecated; do not copy it.

sv_enforceGameBuild locks which GTA V content build clients load. It is startup-only, so changing it requires a full server restart. This file ships the line commented out. When you leave it off, the server serves the vanilla base game with no DLC content (the FiveM docs call this build 1), and does not auto-detect anything newer. When you need DLC content, uncomment it and set the build your assets require. Because the newest supported build changes over time, always check the current supported game-build list in the Cfx.re server-command reference before you launch (for example 3751, but verify against the current list). Do not confuse this number with the FXServer artifact build shown on the artifact download page.

Permissions: the ACE tree

cfg
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 group

FiveM permissions are an ACE tree. ACE stands for Access Control Entry: a rule that says whether a principal may use an object. A principal is who is asking (a player or a group), and an object is what they want to use (usually a command). You build the tree with two directives. add_ace [principal] [object] [allow|deny] grants or denies a principal access to an object. 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 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 defined.

The identifier is the part you change. Players can be identified by identifier.fivem:, identifier.steam:, identifier.license:, or identifier.discord:. Use txAdmin's player record to copy the full value you intend to grant; status shows only the primary identifier. Frameworks layer their own permission names on top of ACE, so verify those names against the official recipe for the exact framework version you run.

You 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.&lt;type&gt;:&lt;id&gt; 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

cfg
sv_licenseKey "changeme"

This 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. The value is a single cfxk_ string. Paste it verbatim with no licensekey: prefix, so the line reads sv_licenseKey "cfxk_yourkeyhere". FXServer accepts the key quoted or unquoted; this course always quotes it for consistency.

Get your key from the Cfx.re Portal at https://portal.cfx.re. That is the current home for license keys. Older guides point at keymaster.fivem.net; use the Portal instead. On the Portal, go to Servers, open the registration keys page, click Generate Key +, enter a display name, and click Generate. The key is free, and you need one even for a localhost-only server.

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.

If something went wrong

SymptomFix
Server refuses to start, console mentions the license keyYou left sv_licenseKey "changeme" as the placeholder, or pasted an invalid key. Get a fresh key from portal.cfx.re and paste the exact cfxk_ string with no licensekey: prefix and no trailing spaces. FXServer accepts the key quoted or unquoted; this course always quotes it.
Your server name and tags never appear in the server browserYou 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 sv_maxclients. Never put a secret behind sets, because sets publishes the value to the public server list.
attempt to index a nil value on boot, or a framework/script errors with a missing export or unknown eventA 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, never a restart or ensuring it twice.
onesync_enabled true does nothing or warns it is deprecatedThat is the old syntax. Use set onesync on. OneSync is not on by default; it is the modern standard every server should set. Without it the cap is 31 slots; onesync on is required for 32 or more, up to 2048.
Nobody can connect after you edited the endpointsYou 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.
Players join but get dropped a moment laterYou are missing endpoint_add_udp. FiveM needs both endpoint_add_tcp and endpoint_add_udp on the same port. UDP carries the gameplay data.
Access denied for user / Unknown database 'fivem'Your mysql_connection_string is wrong or the database does not exist yet. Fix the connection string and create the database before ensuring oxmysql-dependent scripts.
sv_enforceGameBuild change is ignored, or clients get a game build mismatchThat convar is startup-only. Set a value from the live Cfx.re supported game-build list that your assets require, then perform a full server restart. Do not use the FXServer artifact number.
ACE permission works for one command but not anotherThe ACE object is too narrow. add_ace group.admin command allow grants every command. add_ace group.admin command.mycommand allow grants only that one command.
Your admin works until the next restart, then loses accessYou granted the principal in the live console, which is session-only. Add the add_principal line to server.cfg so it survives a restart.
Couldn't find resource (a name you ensured)The folder name and the ensure name must match exactly. Resource-name case matters on Linux hosts; Windows is forgiving, but treat names as case-sensitive everywhere (my_resource is not My_Resource) so a later move to a Linux VPS does not break. Check for a typo or a wrapping zip folder. The resource folder must hold fxmanifest.lua directly.
Two resources both need each other (circular dependency)One must start first, or they need restructuring. Move the shared code into a third resource that both depend on, and ensure that third resource above both.
The command is not recognizedType server commands like restart in the txAdmin Live Console, not in the in-game F8 client console.

What you can do now

  • Place server.cfg at the root of server-data and launch the server with +exec server.cfg, or restart it from txAdmin's CFG Editor.
  • Read the endpoints block and know to change the port, never the 0.0.0.0 IP, and keep both TCP and UDP.
  • 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 (never a secret), setr for client-readable convars, set for everything else.
  • Turn OneSync on with set onesync on, the modern standard every server should set and required for 32 slots or more, and pick a valid 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, paste the cfxk_ string from portal.cfx.re with no prefix, and keep it and mysql_connection_string secret.
  • Open any script's fxmanifest.lua, read its dependencies and shared_script lines, and place it correctly in server.cfg by inspection alone.

Try it yourself