Automatic setup
gm_rdb is a binary module that runs inside SRCDS and exposes Lua state for debugging.
Using the setup wizard (recommended)
Use the built-in setup wizard. The walkthrough should appear when you install the extension for the first time. You can also start it yourself:
- Open the Command Palette (
Ctrl+Shift+P)
- Run GLua: Setup Debugger
- Follow the wizard steps. It will download the correct
gm_rdb binary for your server’s OS and architecture, then guide you through placing the files
You can also click GLuaLS in the status bar to start the setup wizard.
Manual installation
The VS Code extension can set up the debugger for you. Use manual setup only if the extension setup fails.
Step 1: Download and install gm_rdb
Download the correct binary for your server from the GitHub releases page:
| Platform | File |
|---|
| Windows 64-bit | gmsv_rdb_win64.dll |
| Windows 32-bit | gmsv_rdb_win32.dll |
| Linux 64-bit | gmsv_rdb_linux64.dll |
| Linux 32-bit | gmsv_rdb_linux.dll |
Place the binary in garrysmod/lua/bin/ on your server. Create the bin folder if it does not exist. The final path should be garrysmod/lua/bin/gmsv_rdb_*.dll.
Place this loader script at garrysmod/lua/autorun/debug.lua:
garrysmod/lua/autorun/debug.lua
-- [GLuaLS] Auto-managed by GLuaLS extension. Do not edit.
_GLUALS = _GLUALS or {}
if SERVER then
require("rdb")
rdb.activate(21111)
util.AddNetworkString("gm_rdb_exec")
local function normalizeRealm(realm)
realm = string.lower(tostring(realm or "server"))
if realm ~= "server" and realm ~= "client" and realm ~= "shared" then
realm = "server"
end
return realm
end
local function sendClientExec(kind, payload)
net.Start("gm_rdb_exec")
net.WriteString(kind)
net.WriteString(payload)
net.Broadcast()
end
local function runServerChunk(code, chunkName)
local fn, compileErr = CompileString(code, chunkName or "gluals_run_lua", false)
if not isfunction(fn) then
return false, tostring(compileErr)
end
local ok, runtimeErr = xpcall(fn, debug.traceback)
if not ok then
return false, tostring(runtimeErr)
end
return true
end
local function includeServerFile(filePath)
local ok, includeErr = pcall(include, filePath)
if not ok then
return false, tostring(includeErr)
end
return true
end
local function readServerFileForClient(filePath)
local content = file.Read(filePath, "LUA")
if isstring(content) then
return content
end
content = file.Read("lua/" .. filePath, "GAME")
if isstring(content) then
return content
end
return nil, "unable to read file for client execution: " .. filePath
end
function _GLUALS.runLua(realm, code)
realm = normalizeRealm(realm)
if type(code) ~= "string" then
return false, "lua chunk must be a string"
end
if realm == "server" or realm == "shared" then
local ok, err = runServerChunk(code, "gluals_run_lua")
if not ok then
return false, err
end
end
if realm == "client" or realm == "shared" then
sendClientExec("lua", code)
end
return true
end
function _GLUALS.runFile(realm, filePath)
realm = normalizeRealm(realm)
filePath = tostring(filePath or "")
if filePath == "" then
return false, "file path is required"
end
if realm == "server" or realm == "shared" then
local ok, err = includeServerFile(filePath)
if not ok then
return false, err
end
end
if realm == "client" or realm == "shared" then
local clientCode, readErr = readServerFileForClient(filePath)
if not isstring(clientCode) then
return false, tostring(readErr)
end
sendClientExec("lua", clientCode)
end
return true
end
function _GLUALS.refreshFile(filePath)
filePath = tostring(filePath or "")
if filePath == "" then
return false, "file path is required"
end
if not game or not game.ConsoleCommand then
return false, "game.ConsoleCommand is unavailable"
end
local quotedPath = string.format("%q", filePath)
game.ConsoleCommand("lua_refresh_file " .. quotedPath .. "\n")
return true
end
end
if CLIENT then
net.Receive("gm_rdb_exec", function()
local kind = net.ReadString()
local payload = net.ReadString()
if kind == "lua" then
local func, err = CompileString(payload, "gluals_client_exec", false)
if not isfunction(func) then
ErrorNoHalt("[GLuaLS] Client exec compile error: " .. tostring(err) .. "\n")
return
end
local ok, runtimeErr = xpcall(func, debug.traceback)
if not ok then
ErrorNoHalt("[GLuaLS] Client exec runtime error: " .. tostring(runtimeErr) .. "\n")
end
return
end
ErrorNoHalt("[GLuaLS] Unknown exec kind: " .. tostring(kind) .. "\n")
end)
end
This script comes from version 1.0.6 and may be outdated if you use a newer extension version. Use the setup wizard for the latest loader script.
Runtime launch flags
gm_rdb reads these command-line flags when the module loads. You can skip them unless you need the listed behavior.
| Flag | Effect | Default without flag |
|---|
-rdb_allow_remote | Accept debugger connections from non-loopback addresses | Only localhost or loopback connections are allowed |
-rdb_pause_on_activate [seconds] | Pause on the next event after rdb.activate(...) runs. Optional timeout in seconds; use 0 to wait indefinitely. | activate does not pause |
Add these CLI flags to your Garry’s Mod or SRCDS launch options.
Create a launch.json in your .vscode/ folder (or use the VS Code Run & Debug panel → Create a launch.json file):
Attach to a running server
Use attach when the server is already running. Most addon development uses this option.
Use the settings menu instead of editing the JSON file directly. This helps you avoid config mistakes.
{
"version": "0.2.0",
"configurations": [
{
"type": "gluals_gmod",
"request": "attach",
"name": "GMod Attach (SRCDS)",
"host": "127.0.0.1",
"port": 21111,
"sourceRoot": "${workspaceFolder}/../..",
"sourceFileMap": {
"${workspaceFolder}/../../addons": "addons",
"${workspaceFolder}/../../lua": "lua",
"${workspaceFolder}/../../gamemodes/base": "gamemodes/base",
"${workspaceFolder}/../../gamemodes/sandbox": "gamemodes/sandbox"
},
"stopOnEntry": false,
"stopOnError": false,
"realm": "server"
}
]
}
- “sourceRoot”: should point to your garrysmod folder (one level up from scrds)
- “sourceFileMap” should map workspace folders to their corresponding paths, going from the sourceRoot folder.
Edit the configuration above to match your workspace structure. Most setups only need one new line in sourceFileMap.
Addon example:
"${workspaceFolder}": "addons/your-addon-folder"
Gamemode example:
"${workspaceFolder}": "gamemodes/your-addon-folder"
This example covers common addon and gamemode layouts. You can use hardcoded paths, but other developers will need to edit them before using your config.
Launch a server
The launch option is unsupported and may not work on all systems. Use attach instead.
Step 3: Start debugging
- Start your SRCDS server
- In VS Code, open the Run & Debug panel (
Ctrl+Shift+D)
- Select your launch configuration from the dropdown
- Press F5 (or click the green play button)
When VS Code connects, the debug toolbar appears at the top of the screen. The Debug Console opens in the bottom panel.
Configuration reference
Attach configuration
| Property | Type | Description |
|---|
host | string | Server hostname or IP. Default: "127.0.0.1" |
port | number | Port gm_rdb is listening on. Default: 21111 |
sourceRoot | string | Workspace path to map server files to. Default: ${workspaceFolder} |
sourceFileMap | object | Map server paths to workspace paths manually |
stopOnEntry | boolean | Pause at first line when connecting. Default: true |
stopOnError | boolean | Pause when a Lua error is thrown. Default: false |
realm | string | Default realm for code execution ("server" or "client") |
Launch configuration (server process)
The launch option is unsupported and may not work on all systems. Use attach instead.
Includes the above, plus:
| Property | Type | Description |
|---|
program | string | Path to srcds.exe or srcds_run |
args | string[] | Additional server command-line arguments |
cwd | string | Working directory for the server process |
Changing the default port
To make gm_rdb listen on a different port, change this line in debug.lua:
garrysmod/lua/autorun/debug.lua
rdb.activate(<PORT_NUMBER>)
Update "port" in your launch.json to match.
Remote debugging
Do not use the debugger on untrusted or public networks. Use remote debugging only if you understand and accept the risk.
If debugging a remote server, start SRCDS with -rdb_allow_remote, open the gm_rdb port (default 21111) in your server’s firewall, and set host in your launch.json to the server’s reachable address.
Without -rdb_allow_remote, gm_rdb only accepts loopback connections, so remote attach fails.
Do not enable this option unless you understand and accept the risk. If you enable this option on the client and expose your local port, any server could activate the debugger through clientside Lua.
Pause on activation
Do not use the debugger on untrusted or public networks. This option pauses execution once loaded (usually during startup/initial join). If no timeout is provided, execution resumes automatically after 60 seconds if no debugger connects.
rdb.activate(...) does not pause execution by default. The debugger may miss the server or client startup sequence unless you connect fast.
To pause on the next hook event after rdb.activate(...) runs, add -rdb_pause_on_activate to the server startup arguments or client Steam launch options. You can provide a timeout in seconds.
-rdb_pause_on_activate
-rdb_pause_on_activate 120
-rdb_pause_on_activate 0
-rdb_pause_on_activate pauses on activation and resumes after 60 seconds if no debugger connects.
-rdb_pause_on_activate 120 pauses on activation with a 120-second timeout.
-rdb_pause_on_activate 0 pauses until a debugger connects.
Use this when you need to capture the server or client startup sequence.
If you enable this option on the client, any server could activate the debugger and freeze your game.