Building Your Server Executable
A dedicated server executable is a standalone build of your game that runs the data of game world/state without rendering graphics, playing audio, or accepting local player input. It exists solely to simulate the game state and communicate with connected clients over the network.
Why a Separate Build
Section titled “Why a Separate Build”Shipping your game client as the server is one of the most common mistakes first-time studios make. A game client includes rendering pipelines, audio engines, input handling, UI frameworks, and asset bundles that a server will never use. All of that wastes disk space, memory, and CPU cycles on a machine that is paid for by the hour.
A dedicated server executable should:
- Run without a GPU or display
- Use a fraction of the client’s memory footprint
- Start faster and consume fewer resources
- Have no dependency on client-side libraries (DirectX, Vulkan, OpenAL, etc.)
Headless Mode
Section titled “Headless Mode”“Headless” means the server runs without creating a window or initializing any graphics context. Most game engines support this natively.
If your engine supports a headless build target, use it. If not, you need to ensure your server does not attempt to initialize any rendering or audio subsystem at startup. A server that silently requires a GPU will fail on every standard hosting machine.
Creating a Slim Server Build
Section titled “Creating a Slim Server Build”Your primary goal is to minimize the resources a server requires.
Code Separation
Modularize your code so client and server components are clearly separated. This makes it easier to strip rendering, audio, and other client dependencies from the server build.
Reduced Asset Footprint
Textures, sounds, UI sprites, and other assets only needed by the client should not exist in the server build. This results in faster deployment, faster updates, and lower disk usage on hosting machines.
Leverage Your Engine’s Build Options
Most modern engines (Unreal, Unity, Godot) offer dedicated server build targets or headless packaging options. If your engine does not natively support this, script the packaging process yourself to exclude client-only assets and dependencies.
See the engine-specific guides for details:
Build Pipelines
Section titled “Build Pipelines”Ideally, your server has its own build pipeline separate from the client. This gives you full control over what ships in each build.
In practice, many teams maintain a single project that conditionally compiles the server build. This is a reasonable middle ground. Use preprocessor defines, build flags, or scripted packaging to strip client-only code and assets at build time.
What matters is that you can reliably produce a server build that does not include client overhead, and that your CI/CD can produce both builds automatically.
Startup Arguments
Section titled “Startup Arguments”Your server executable should accept command-line arguments for at minimum:
- Port number (e.g.,
-port 27015) - Config file path (e.g.,
-config /path/to/server.json) - Max players (e.g.,
-maxplayers 32) - Map or world (e.g.,
-map arena_01) - Log verbosity (e.g.,
-loglevel info)
Hosting platforms rely on startup arguments to configure servers dynamically. If your server only reads from a config file with no argument overrides, it becomes much harder for platforms to manage fleets of servers with different settings.
Graceful Shutdown
Section titled “Graceful Shutdown”When a hosting platform needs to stop your server, it sends a POSIX signal. Your server must handle these correctly.
SIGTERM is the standard “please shut down” signal. When your server receives it:
- Stop accepting new player connections
- Notify connected players (if possible)
- Save all world/game state
- Flush any pending log output
- Exit with code 0
SIGINT (Ctrl+C) should behave the same way.
If your server does not handle SIGTERM, the hosting platform will wait a timeout period and then send SIGKILL, which terminates the process immediately with no chance to save. Players lose progress, save files may corrupt, and crash recovery kicks in unnecessarily.
Exit Codes
0means clean shutdown. The hosting platform knows everything is fine.- Non-zero means something went wrong. The platform may log it, alert the owner, or trigger automatic restart behavior.
Use meaningful exit codes if possible. At minimum, distinguish between “clean shutdown” (0) and “crashed” (1).
Process Lifecycle
Section titled “Process Lifecycle”Hosting platforms treat your server as a managed process. Understand what they expect:
-
Start: The platform launches your executable with specific arguments. Your server should be ready to accept connections within a reasonable time (under 60 seconds for most games, ideally much faster).
-
Run: Your server runs until told to stop. It should not exit on its own unless something is genuinely wrong. An idle server with zero players is still a running server, but you could pause simulation or reduce tick rate to save resources if your game supports it.
-
Stop: The platform sends SIGTERM. Your server shuts down gracefully.
-
Restart: The platform stops and starts your server. This should work cleanly every time. If your server leaves behind lock files, temp files, or corrupted state that prevents a clean restart, that is a bug you need to fix.
Do not implement your own auto-restart logic. The hosting platform handles restarts, and competing restart mechanisms cause unpredictable behavior.
More Advanced Hosting platforms like Nodecraft may support additional lifecycle hooks for Just In Time Servers, but the above is the baseline expectation for any server build.