On this page

Build

build transpiles every TypeScript file under src/ to Lua and writes the result into the Defold project tree — a one-shot compile. For the incremental loop you run while editing, see watch.

bunx @defold-typescript/cli build

What it does

Each source becomes exactly one output. A file with an export default defineScript({...}) (or defineGuiScript/defineRenderScript) lifecycle factory becomes a Defold script component (src/main.ts -> src/main.ts.script); a plain module with no factory becomes a Lua module (src/util.ts -> src/util.lua) — a generated artifact you never edit or reference by hand, only ever the src/util.ts you author. Your import becomes a Lua require that resolves against that emitted module, so a shared module must be built before the script importing it will run. Open the project in the Defold editor (or run it headlessly, below) to play it.

When a source uses a runtime helper TypeScript-to-Lua provides (Object.keys, object spread, and similar), the build also writes a lualib_bundle.lua at the output root automatically; the generated Lua's require("lualib_bundle") resolves against it.

Because the output kind is the factory a source calls, adding or removing a factory switches the artifact (src/main.lua becomes src/main.ts.script, or the reverse). build and watch prune the stale alternative for you, so a kind switch never leaves the previous output behind. Every generated file carries a trailing --# defold-typescript:generated marker; on a full build the tool warns, never deletes about any marked .lua or .ts.* output whose TypeScript source no longer exists, so a deleted or renamed source's orphaned Lua surfaces for you to remove (the warning names the file and the source to restore). Hand-authored Lua, which lacks the marker, is never flagged or touched.

A full build also warns when a .go/.collection component: references a mesh source asset (.gltf/.glb/.dae) directly. Those are imported into a .model component, not added as components — the editor rejects the direct form, but Bob's headless build accepts it and the game object fails at runtime. The warning names the scene file and the offending path; wrap the mesh in a .model (with a materials block) and point the component at the .model.

build never narrows the API surface — it builds against whatever entrypoint your tsconfig names, the full @defold-typescript/types by default. Opt into per-directory narrowing with wall.

The everyday commands carry no version tag: inside an installed project bunx resolves the @defold-typescript/cli that init pinned, so the build runs the version locked alongside your @defold-typescript/types. Reserve @latest for init and the deliberate upgrade path (see code editor setup).

Flags

  • --json — emit the build result as a single JSON object (including the warnings array) for agents and scripts. See Agent runbooks.

Headless builds (no editor)

build transpiles TypeScript to Lua; to compile and run the Defold project itself from the command line — no editor — drive Defold's headless build tool (bob) through the defold subcommand:

bunx @defold-typescript/cli defold resolve   # fetch library dependencies
bunx @defold-typescript/cli defold build     # debug build into build/default
bunx @defold-typescript/cli defold bundle    # bundle a platform target

The first run downloads a version-matched bob.jar into a cache dir ($DEFOLD_TYPESCRIPT_CACHE/bob when set, otherwise $XDG_CACHE_HOME/defold-typescript/bob, falling back to ~/.cache/defold-typescript/bob) and reuses it afterward. bob needs a JVM. It resolves one in order: the --java <path> flag (or DEFOLD_JAVA), then java on your PATH, then the JDK bundled inside an installed Defold editor. If none resolve, the command errors and names all three. Native-extension projects can pass --build-server <url>. bob's exit code propagates, so a failed build fails the command.

Like the engine launcher, the bob version tracks the latest stable Defold release. A project pinned to an older Defold version is a known limitation.