Why do you personally prefer Defold over Unity for 2D games?

I also strongly prefer statically typed languages, and I also keep being drawn back to Defold for its other attributes despite how much I dislike working without compile-time type safety. I’m a full-time software engineer, and in the US at least, the vast majority of us use statically typed languages daily. Like others have said:

  • Lua in Defold feels like going back to untyped JavaScript
  • I tried Teal, but Teal just isn’t there today in any realistic sense (I spent many hours converting thousands of lines across two projects before deciding Teal is untenable)
  • I eventually hit a middle-ground via thoroughly annotating plain Lua with LuaCATS comments.

For others in the same boat, some things that have helped:

First, I found Teal to be even more verbose than LuaCATS annotations. It’s slightly more expressive, but not worth the cost.

Second, a more aggressive .luarc.json can help highlight type errors before runtime. This is the one I use:

{
    "workspace.library": [
        "types/defold"
    ],
    "workspace.ignoreDir": [
        ".git",
        ".vscode",
        "build",
        ".internal"
    ],
    "workspace.checkThirdParty": false,
    "runtime.version": "LuaJIT",
    "diagnostics.globals": [
        "hash",
        "vmath",
        "pprint"
    ],
    "$schema": "https://raw.githubusercontent.com/LuaLS/vscode-lua/master/setting/schema.json",
    "diagnostics.severity": {
        "assign-type-mismatch": "Error",
        "param-type-mismatch": "Error",
        "return-type-mismatch": "Error",
        "cast-type-mismatch": "Error",
        "undefined-field": "Error",
        "undefined-global": "Error",
        "missing-return": "Error"
    },
    "type.weakUnionCheck": true,
    "type.castNumberToInteger": false,
    "type.castIntegerToNumber": true,
    "diagnostics.disable": [
        "lowercase-global"
    ]
}

The types/defold reference is populated via GitHub - astrochili/defold-annotations: Defold annotations generator for Lua Language Server · GitHub . Third-party extensions (for example, fastnoise) can be used unsafely via adding them to "diagnostics.globals" or safely by getting an LLM to write some type annotations for them that you stick in types/whatever.lua.

Finally, I have found LLMs to be useful in annotating my own code with LuaCATS - to me, one of the main drawbacks of both LuaCATS and Teal is having to define types separately from where you’re using them, essentially writing everything twice. It gets in the way of quick development. So writing scripts, then having an LLM annotate the comments without changing any of the code, has been helpful. Gemini 3 Pro seems to understand Lua the best as of today.

This is a positive for me re: Defold. I prefer a small, tight, fast, well-tested, stable core that can be extended as necessary. Godot and Unity are both littered with buggy out-of-the-box systems. Defold has excellent support for native extensions already, and I think the work the team is doing to increase the power of editor scripts is strategic & smart. That said, it’s objectively true that Defold has fewer solid 3rd party anythings so for many classes of games that need them, Defold is a non-option.

As to the specific reasons I love Defold despite all the above with Lua:

  • It sits somewhere between “game engine” and “game library” in a nice spot that gives you some minimal visual tools, while still promoting a code-and-data-first workflow.
  • Reliable and fast, both at runtime and build time. I can edit things in vscode and know that the filesystem changes are reflected in Defold, without having to shut it down and restart it each time and without expecting it to crash when something else touches a file.
  • The patterns that it encourages are simple and elegant, without forcing you into any one particular paradigm. It’s easy to build static (global) modules or bags of state, easy to pass messages, easy to create instances, easy to pool objects, etc. You can define behaviors Unity-style via several scripts on a game object, or via code composition with Lua modules.
  • While not statically-typed, Lua is undeniably elegant.
  • Its reliable monthly release cadence is amazing; releases consistently fix bugs that are impacting me or ship major features that unlock things for me.
  • The core team is friendly, welcoming, communicative, receptive, smart.
  • Though small, the community is all the above as well.

The IDE has regressed this year with lots of small bugs from new features (selection state becomes de-synced between the outline view and the properties form, keyboard navigation is broken for certain types of inputs, focus is handled inconsistently, the overloading of what double clicks and hotkeys do in the outline view has made common editing workflows harder). And the broader architecture comes with historical baggage (GOs vs Collections, GO vs GUI, lack of GO string properties). But these are rough edges I’m willing to deal with.

11 Likes