Defold contains an integrated Lua debugger with an inspection facility. Together with the built-in profiling tools it is a powerful tool that can help finding the cause of bugs in your game logic or help analyze performance issues.
The simplest way to debug your game in Defold is to use print debugging. Use print() or pprint() statements to watch variables or indicate the flow of execution. If a game object without a script acts weird, you can just attach a script to it with the sole purpose of debugging. Using any of the printing functions will print to the Console view in the editor and to the game log.
In addition to printing, the engine can also draw debug text and straight lines on the screen. This is done by posting messages to the @render socket:
-- Draw value of "my_val" with debug text on the screen
msg.post("@render:", "draw_text", { text = "My value: " .. my_val, position = vmath.vector3(200, 200, 0) })
-- Draw colored text on the screen
local color_green = vmath.vector4(0, 1, 0, 1)
msg.post("@render:", "draw_debug_text", { text = "Custom color", position = vmath.vector3(200, 180, 0), color = color_green })
-- Draw debug line between player and enemy on the screen
local start_p = go.get_position("player")
local end_p = go.get_position("enemy")
local color_red = vmath.vector4(1, 0, 0, 1)
msg.post("@render:", "draw_line", { start_point = start_p, end_point = end_p, color = color_red })
The visual debug messages adds data to the rendering pipeline and is drawn as part of the regular render pipeline.
"draw_line" adds data that is rendered with the render.draw_debug3d() function in the render script."draw_text" is rendered with the /builtins/fonts/debug/always_on_top.font that uses the /builtins/fonts/debug/always_on_top_font.material material."draw_debug_text" is the same as "draw_text", but it’s rendered in a custom color.Note that you probably want to update this data every frame so posting the messages in the update() function is a good idea.
The Lua debugger is available in native debug and headless builds. Use an engine from the same Defold version as the editor. Release and Web builds do not support attaching the debugger.
To run the debugger, select Debug ▸ Start/Attach. This starts the game with the debugger attached, or attaches to an already running game. When starting a game for debugging, the editor installs enabled breakpoints before startup scripts run, so you can set a breakpoint in init() before launching.
To attach to a device, select it under Project ▸ Targets, then choose Debug ▸ Start/Attach. Attachment pauses at the next Lua line. The editor sets up the debugger connection automatically for supported local and remote targets. See Remote targets for connection requirements, or learn how to connect an external debugger.

As soon as the debugger is attached, you have control of the execution of the game through the debugger control buttons in the console, or through the Debug menu:


end statement below the line with the call to the function nextspawn():

Stepping follows Lua source lines. A step can revisit the same line, for example when a loop repeats, so it does not always advance to the next line in the file.
nextspawn():


To set or clear a breakpoint, click in the column just right of the line numbers in the code editor. You can also select Edit ▸ Toggle Breakpoint from the menu.
Enabled checkbox. Disabled breakpoints appear hollowed out to indicate they are inactive.


To edit the breakpoint condition, right-click in the column just right of the line numbers in the code editor, or select Edit ▸ Edit Breakpoint from the menu.

You can also change values through assignments, for example self.score = 100 in a frame where self is available. Evaluated code has the same effects on game state as code executed by your game.
_G to inspect globals, and expand tables or self to inspect their fields. The editor preserves expanded paths, selection, and scroll position when stepping, switching frames, or refreshing after evaluation, while fetching current values.The engine provides a native Debug Adapter Protocol (DAP) server over TCP. For an external DAP client, start the listener in a native Defold debug or headless engine, then connect the client to the engine’s address and port. The editor handles listener setup automatically when you use Debug ▸ Start/Attach.
The current editor cannot connect to older engines that only support MobDebug. No require "builtins.scripts.mobdebug" call is needed or available in current versions.
Build your project first. From the project directory containing build/default/game.projectc, run the native debug engine with these startup configuration overrides:
dmengine --config=debugger.enabled=1 \
--config=debugger.port=8172 --config=debugger.wait=1
Connect your DAP client to 127.0.0.1:8172. The engine waits for the client to configure breakpoints before running startup scripts.
| Setting | Default | Purpose |
|---|---|---|
debugger.enabled |
0 |
Set to 1 to start the listener during engine startup. |
debugger.address |
127.0.0.1 |
IPv4 address on which to listen. The default accepts connections from the same computer. |
debugger.port |
8172 |
TCP listening port. Use 0 to select an available port. |
debugger.wait |
0 |
Set to 1 to wait for the debugger client’s configuration before running startup scripts. |
You can also add these values to the Debugger section of game.project. The editor configures the listener automatically for Debug ▸ Start/Attach, so manual configuration is only needed when starting the listener yourself.
The engine log reports the selected address and port. With debugger.wait=0, the game starts immediately and you can attach later. With debugger.wait=1, it waits until the client has finished configuring the session, including breakpoints. For local debug launches, the editor selects an available port automatically.
Disconnecting a client resumes execution and leaves the listener available for another attachment. A disconnect while waiting for startup configuration also releases the engine. If the listener cannot start, the engine logs the error and continues startup; you can retry from Lua with debugger.start(0) to select an available port.
To enable the listener from a script without restarting the game:
if debugger then
local port = debugger.start(0)
print("DAP listener port:", port)
end
debugger.start([port [, address]]) returns the listening port immediately. It does not wait for a client or pause the game. Omitted arguments use debugger.port and debugger.address; passing 0 selects an available port. Repeated calls return the existing listener’s port and do not change its address or port. The debugger module is provided by native debug and headless engines.
The port must be an integer from 0 to 65535. Pass nil as the first argument to override only the address. Invalid arguments or a failure to bind the listener raise a Lua error.
For a direct connection from another computer, bind the listener to the device’s IPv4 interface or to 0.0.0.0 (all IPv4 interfaces). For example, use debugger.start(8172, "0.0.0.0"), or add --config=debugger.address=0.0.0.0 to the startup command above. Connect the client to the device’s actual IP address and allow TCP access to the listening port. 0.0.0.0 is a bind address, not the address to enter in the client.
The Defold editor requests this remote bind automatically and uses port 8172 + project.instance_index for remote targets. It cannot discover a dynamically selected remote port. If you already started the remote listener on localhost or a different port, restart the engine before attaching from the editor.
The debugger can evaluate Lua and has no authentication. Enable remote access only on a trusted development network.
Use a client that supports attaching directly to a DAP server over TCP. Configure its source mapping to the folder containing game.project (the DAP localRoot attach argument). Start the engine listener first, then attach the client.
Install the Lua Debug extension (actboy168.lua-debug), open the folder containing game.project in VS Code, and add this configuration to .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Defold Lua",
"type": "lua",
"request": "attach",
"address": "127.0.0.1:8172",
"debugServer": 8172,
"localRoot": "${workspaceFolder}",
"stopOnEntry": false
}
]
}
If VS Code opens a .script, .gui_script or .render_script file as plain text, select Lua from the language indicator in the status bar before setting breakpoints.
Set a breakpoint, for example in a script’s init() function. Start the engine using the startup command above, then select Attach to Defold Lua in VS Code’s Run and Debug view. With debugger.wait=1, the engine runs startup scripts after the client has installed the breakpoints. Set stopOnEntry to true if you also want to pause at the next Lua line after attachment.
VS Code’s debugServer setting connects directly to the engine’s local TCP listener. The address field is required by the Lua Debug extension’s attach configuration. If you change the listener port, update both fields. localRoot must point to the project folder so the client can map the engine’s Lua source names to your files.
For a remote engine, forward its DAP port to localhost and put the forwarded port in both fields, or use a DAP client that connects directly to the remote host.

When working with multiple breakpoints across different scripts, the Breakpoints tab provides a centralized view for managing all your breakpoints in one place.
For working with individual breakpoints:
Select multiple breakpoints using Ctrl/Cmd+click or Shift+click, then right-click to perform bulk actions. You can edit conditions across several breakpoints simultaneously, toggle their active state, or remove them entirely.
The toolbar buttons allow you to enable, disable, or toggle all breakpoints at once, useful when you want to run your game without stopping but don’t want to lose their positions. You can also remove all when you’re done with your debugging session.
Lua comes with a debug library that is useful in some situations, particularly if you need to inspect the innards of your Lua environment. You can find more information about it in the chapter about the Debug Library in the Lua manual.
If you encounter an error or if your game does not behave like expected, here is a debugging checklist:
Check the console output and verify that there are no runtime errors.
Add print statements to your code to verify that the code is actually running.
If it’s not running, check that you have done the proper setup in the editor required for the code to run. Is the script added to the right game object? Have your script acquired input focus? Are the input-triggers correct? Is the shader code added to the material? Etc.
If your code is depending on the values of variables (in an if-statement, for example), either print those values where they are used or checked, or inspect them with the debugger.
Sometimes finding a bug can be a hard and time consuming process, requiring you to go through your code bit by bit, checking everything and narrowing down the faulty code and eliminating sources of error. This is best done by a method called “divide and conquer”:
Happy hunting!
If you have problems with physics and collisions aren’t working as expected it is recommended to enable physics debugging. Check the Debug checkbox in the Physics section of the game.project file:

When this checkbox is enabled Defold will draw all collision shapes and contact points of collisions:
