Automating the Defold editor

The Defold Editor opens up a special server for automated actions. HTTP API controls the opened project. Use it for editor commands, builds, project resources, previews, preferences, console output, documentation search, or editor-script integrations. To inspect or control the running game instead, use the engine service or a runtime automation API.

The editor HTTP API is experimental and may change between Defold versions. The /openapi.json document generated by the running editor is the source of truth for its available operations and schemes.

Starting the editor from an external tool

An external tool needs the editor executable and the absolute path to the project’s game.project file.

Installed Defold versions can be located through installations.json, as described in the Editor manual. Its launcherPath field contains the executable to start. Pass the game.project path as the first positional argument to open that project directly.

The optional --port or -p argument selects the editor server port. Omitting it lets Defold choose an available port and is usually preferable when several projects may be open.

# Linux
/path/to/Defold/Defold --port 8181 /absolute/path/to/project/game.project
# macOS
/path/to/Defold.app/Contents/MacOS/Defold --port 8181 /absolute/path/to/project/game.project
# Windows
C:\path\to\Defold\Defold.exe --port 8181 C:\absolute\path\to\project\game.project

The editor is a graphical desktop application. Start it in an interactive user session with access to the display. Use Bob when a graphical session is unavailable, such as in headless CI, or for compile-only automation and creating standalone bundles.

After starting the editor, wait until the project has opened and .internal/editor.port exists. Then poll /openapi.json until it returns a valid document. Do not assume that creating the process means the project is ready.

Locating the editor server

The editor starts a local HTTP server while a project is open. Select Help ▸ Open Editor Server to open its home page in the default browser:

The selected port is written inside the project to:

.internal/editor.port

The examples and commands in this manual will from now on refer to these shell variables:

PORT="$(cat .internal/editor.port)"
BASE_URL="http://127.0.0.1:$PORT"

The port file belongs to the current editor session. Read it again after restarting the editor.

The editor server is a trusted local control interface. Do not expose it through a public address, port forward, or untrusted tunnel.

Discovering operations through OpenAPI

The only Defold-specific bootstrap information an external tool should need is the editor port and the OpenAPI document:

curl -sS "http://127.0.0.1:$(cat .internal/editor.port)/openapi.json"

The returned OpenAPI 3.0.3 document describes the operations supported by the running editor version, including paths, methods, parameters, command names, request formats, responses, status codes, and authentication requirements.

List the documented paths:

curl -sS "$BASE_URL/openapi.json" |
  jq -r '.paths | keys[]'

List the available editor commands:

curl -sS "$BASE_URL/openapi.json" |
  jq -r '
    .paths["/command/{command}"].post.parameters[]
    | select(.name == "command")
    | .schema.enum[]
  '

A version-aware integration should verify each required operation and configure requests from the returned schema. We advise against maintaining a supposedly exhaustive copy of endpoint or command names, as this can get outdated.

Project-defined routes also appear in /openapi.json when their editor scripts provide an OpenAPI operation description.

Executing editor commands

Editor commands are invoked through:

POST /command/{command}

For example, the current build command compiles and runs the project:

curl -sS \
  -X POST \
  "$BASE_URL/command/build" |
  jq

A successful build returns a structured result:

{
  "success": true,
  "issues": []
}

A failed build returns HTTP status 422 with issues such as:

{
  "success": false,
  "issues": [
    {
      "message": "Example compiler message",
      "severity": "error",
      "resource": "/main/player.script",
      "range": {
        "start": {
          "line": 12,
          "character": 4
        },
        "end": {
          "line": 12,
          "character": 17
        }
      }
    }
  ]
}

The available fields depend on the error. Use the resource path and source range when present, but also handle issues that contain only a message.

Commonly useful commands, when listed by the running editor, include:

build
Compile and run the project.
clean-build
Clear the build cache, then compile and run. Use this only when an ordinary build behaves inconsistently or appears to miss changes.
build-html5
Build the project for HTML5 and make the output available through the editor server.
fetch-libraries
Download and reload project dependencies.
hot-reload
Reload modified resources into a running game.
reload-extensions
Reload editor scripts.
debugger-start, debugger-stop, and the debugger step commands
Control a debug session and the running project.

Exact names and availability depend on the editor version and current editor state; discover them from /openapi.json.

Commands that operate on project resources synchronize external file changes before execution.

Command responses and asynchronous work

The command operation documents response codes in the current OpenAPI schema.

Status Meaning
200 The command completed and returned a result
202 The command was accepted and continues asynchronously
403 The command is not active in the current editor state
404 The command is not available
422 Build or validation failed
500 An internal editor error occurred

An HTTP 202 response is not proof that the requested result exists. Wait for the relevant output, resource, console marker, or served URL and enforce a timeout.

Building HTML5

If the current OpenAPI document lists build-html5, invoke it through the command operation:

curl -sS \
  -X POST \
  "$BASE_URL/command/build-html5"

The command runs asynchronously and normally returns HTTP 202. After the build completes, the editor serves it at:

http://127.0.0.1:<editor-port>/html5/

Wait until the URL is available before starting browser tests. See Browser tests for HTML5 for more details.

Searching API documentation

When present in /openapi.json, the /ref operation searches API documentation included with the running editor version. It provides names and signatures that match that version.

For example, to search for a function, use:

curl -sS \
  --get \
  --data-urlencode "q=go.animate" \
  "$BASE_URL/ref" |
  jq

Filter by environment and language:

curl -sS \
  --get \
  --data-urlencode "environment=runtime" \
  --data-urlencode "language=Lua" \
  --data-urlencode "q=collision message|raycast" \
  "$BASE_URL/ref" |
  jq

The search parameters are:

environment
editor, runtime, or comma-separated values.
language
Lua, C, C++, or comma-separated values.
q
A case-insensitive expression. Whitespace represents AND, while | represents OR.

The are also condensed documentation resources: LLM documentation index links to official manuals, API namespaces, and examples and the full LLM documentation lists complete documentation to support offline search and local indexing.

AI agents should prefer though specified searches instead of retrieving an entire reference when only one API or message is needed, in order to save on tokens and have a better prepared and clean context for a given task.

Reading console output

Read the editor console as JSON:

curl -sS "$BASE_URL/console" | jq

The response contains console text in lines and semantic regions in regions, including errors, evaluation results, and resource references.

To follow console output continuously, use:

curl -N "$BASE_URL/console/stream"

The stream includes existing console lines and then remains open for new output. Close it after receiving a completion marker or error, detecting process termination, or reaching a timeout or line limit.

For test-result framing and failure classification, see Automated testing and verification.

Rendering scene previews

The Defold editor (since 1.13.1) can render a supported scene resource “screenshot” to PNG through command /preview/{path}:

mkdir -p build/automation

curl -sS \
  "$BASE_URL/preview/main/main.collection?width=1280&height=720" \
  --output build/automation/main-preview.png

This renders the main collection from the open Basic 3D template project in a default initial view:

You can use render to get previews of resources that utilise the visual scene editor, for example one can render a model component in the same way, that allows to verify it’s look or e.g. shader correctness:

curl -sS \
  "$BASE_URL/preview/assets/models/cube.model?width=1280&height=720" \
  --output build/automation/cube-preview.png

The path after /preview/ does not include a leading slash. The optional dimensions default to the project display size and must be between 1 and 4096.

Status Meaning
200 The preview was rendered
400 The dimensions are invalid
404 The resource was not found
422 The resource is not loaded or does not support scene previews

Previews might be very useful for visual analysis of the project - checking level layouts, GUI layouts, shader and lighting setup, visual regressions, or create documentation thumbnails.

An editor preview is not a screenshot of the running game. It does not verify dynamically created objects, runtime post-processing, or platform-specific rendering. Use a runtime screenshot when those elements are needed.

Executing editor Lua

The authenticated POST /eval operation executes Lua in the editor extension environment. The per-session bearer token is stored in:

.internal/editor.token

Read the token and execute code:

TOKEN="$(cat .internal/editor.token)"

curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: text/plain" \
  --data-binary 'print(editor.version) return editor.platform' \
  "$BASE_URL/eval"

Printed output and return values are returned as text. Typical responses are:

Status Meaning
200 The code was executed
401 The bearer token is missing or invalid
422 The Lua code could not be parsed or executed
503 The editor extension environment is not ready

A client may retry after 503, but it should use a bounded number of attempts. Correct the code before repeating a request that returned 422.

Evaluated code can use the Editor API and the editor scripting environment. It cannot use game runtime APIs such as go.* to manipulate a running game. Use a runtime test, debugger, browser test, or runtime automation API for gameplay.

Modifying resources and files

Many Defold source resources use text formats and can be edited via any text editing tool. For modifying Defold project structured resources prefer editor transactions.

Change Preferred method
Lua, shader, JSON, or another known text format Direct file modification
Unsaved text in an open editor tab editor.get() and editor.transact()
Collection, game object, GUI, atlas, or another structured resource Editor transaction
Repeatedly generated content Standalone generator
Repeatable project operation Editor command or custom HTTP endpoint
CI-only transformation Standalone script run before Bob

Inspect a resource before changing it:

curl -sS \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: text/plain" \
  --data-binary '
    local path = "/game.project"
    pprint(editor.properties(path))
    return editor.get(path, "path")
  ' \
  "$BASE_URL/eval"

Check editor.can_get(), editor.can_set(), and the other editor.can_*() functions before performing a transaction.

Use editor.execute() in editor Lua to run a formatter, validator, or generator:

local output = editor.execute(
  "python3",
  "scripts/generate_levels.py",
  {
    out = "capture"
  }
)

print(output)

When the command does not modify project resources, set reload_resources = false to avoid an unnecessary reload.

Do not modify files in .internal/ or generated content in build/.

Preferences

Editor preferences can be read and written through the path documented in OpenAPI, currently /prefs/{path}.

You can for example read the configured code font size:

curl -sS "$BASE_URL/prefs/code/font/size" | jq

Or set it to e.g. 16:

curl -sS \
  -X POST \
  -H "Content-Type: application/json" \
  --data '16' \
  "$BASE_URL/prefs/code/font/size"

The editor validates the value against its preference schema. An invalid path or value returns HTTP 400.

Preferences are persistent user or project-user settings, not project configuration stored in game.project. If automation needs to change a preference temporarily, save the previous value and restore it afterward.

Project-defined routes

Editor scripts can define additional routes with get_http_server_routes(). An optional OpenAPI operation table exposes a route through the same /openapi.json document as built-in operations.

Project-defined routes can provide content generation, validation, reports, localization checks, resource analysis, project-specific tests, or a smaller interface for an IDE or external controller.

A good route should perform one clearly named operation, validate its input, return a structured result, be idempotent where possible, and limit expensive work.

Project-defined routes are not automatically protected by the /eval token. Add project-specific authentication and safety checks when a route performs sensitive operations.

Lifecycle hooks

Hooks are functions that can be run before and after builds, before and after bundle creation, and when a game process starts or terminates. A project can contain one hooks.editor_script file in its root. Only the root hook file receives these events, giving the project one place to define their order.

local M = {}

local function validate_project()
  print(editor.execute(
    "python3",
    "scripts/validate_project.py",
    {
      out = "capture",
      reload_resources = false
    }
  ))
end

function M.on_build_started(opts)
  validate_project()
end

function M.on_build_finished(opts)
  print("Build successful:", opts.success)
end

return M

An error raised from on_build_started() stops the editor build. Lifecycle hooks run only in the editor; put shared validation and generation logic in standalone scripts that can also be invoked from CI.

Security and compatibility

Treat the entire editor server as a trusted local interface:

Engine Server

The editor server belongs to the editor process. A running game has a different port and different responsibilities, described in the engine service and runtime HTTP API manual.