11 Installation
Yuris Cakranegara edited this page 2026-08-22 20:59:01 +07:00

Installation

Requirements

Defold 1.12.4 or newer. 1.12.4 is where zlib.inflate learned to read a gzip wrapper, which is what decodes the compressed frames the server sends above 1KiB. CI runs 1.13.0. The SDK itself is pure Lua and runs on both native and HTML5 targets.

Install

Add both of these to your game.project dependencies:

https://git.nokopia.com/yuris/spacetimedb-defold/archive/v4.0.2.zip
https://github.com/defold/extension-websocket/archive/refs/tags/4.2.4.zip

Then Project ▸ Fetch Libraries. That is the whole installation, on every target including HTML5. The archive also carries README.md and game.project, but include_dirs = stdb is what Defold mounts, so require("stdb.init") is the only thing it puts on your require path.

Three things worth knowing, each learned by actually building a separate consumer project against the release:

  • Pin a tag, not main. Defold's own guidance, and it means a library change cannot break your build without you choosing it.

  • extension-websocket is not optional and not automatic. Defold does not resolve dependencies transitively, so a project that lists only this SDK compiles fine and then fails at connect with extension-websocket missing: add it to game.project dependencies.

  • Private repo on Forgejo? Append the token as a query parameter, the same shape Defold documents for GitLab. Basic auth in the URL (https://user:token@…) is not a reliable substitute. Forgejo's archive endpoint validates the query token, and a bad one gets a plain 401, while URL credentials are handled inconsistently.

    https://git.nokopia.com/yuris/spacetimedb-defold/archive/v4.0.2.zip?token=<access-token>
    

Use at least 4.2.4 of extension-websocket. Earlier releases dropped the Sec-WebSocket-Protocol header on HTML5, and SpacetimeDB answers 400 no valid protocol selected without it (#67, fixed by #68).

The one HTML5 difference

Headers do not exist on HTML5, so the token goes in the URL. A browser's WebSocket cannot send an Authorization header, and extension-websocket drops params.headers silently. The connection then succeeds as a brand new anonymous identity, so nothing fails loudly and the player's identity is quietly gone. Verified against 2.8.2, ?token=<jwt> authenticates to the same identity as the header, so connect switches to the query parameter on HTML5 and keeps the header everywhere else (a token in a URL can land in access logs). This one is permanent. Emscripten's WebSocket API has no way to set request headers.

Nothing about it needs your attention. The SDK picks the right route per target.

HTML5 is tested

The full smoke client passes in headless Chromium. It connects, subscribes and calls a reducer, restarts the server and replays the subscription, drops one query set while a second still holds the row, calls procedures and a one-off query, reads an identity-keyed table and an event table, and finishes with a bulk apply, which is the phase that prints the run's single SMOKE: PASS. The subprotocol the handshake offers is asserted, not merely printed, since it is the only place the wire is observable from outside the page. The row id below is a server autoinc, so it differs from run to run:

[handshake] -> subprotocol=v2.bsatn.spacetimedb
[handshake] <- 101 Switching Protocols
[html5] SMOKE: PHASE2 OK survived restart; row id=… restored
[html5] SMOKE: PHASE4 OK procedure round trip; failure surfaced as an error; per-table API: 1 insert(s), 1 update; one-off query returned … encoded BSATN row(s)

Installed? Quickstart goes from here to a connected game.