Publishing

Hosting & Deploys

metaloot deploypublishes a folder of static files to Metaloot's edge hosting. Your game gets its own subdomain, atomic deploys, aggressive caching, and the platform routes — auth, multiplayer, and the asset proxy — served from the same origin.

How a Deploy Works#

  • The CLI locates your build output: --dir if given, then the outDir from metaloot.json, then dist, then build — each must contain an index.html. For a plain HTML project, pass --dir .. Use --no-build to skip your build script.
  • Dotfiles (except .well-known), node_modules, .DS_Store, and Thumbs.db are skipped automatically.
  • Files upload in parallel (8 at a time, 3 retries) to presigned URLs — the CLI never proxies your bytes.
  • A finalize step flips the site to the new deploy atomically: players either get the old version or the new one, never a mix. The deploy id is part of the edge cache key, so stale files cannot leak across versions.
metaloot deploy                       # deploy the current folder's game
metaloot deploy --dir . --no-build    # plain HTML, no build step
metaloot deploy --game <game-id>      # target a game created on the portal
metaloot deploy --name "My Game"      # set the title on first deploy

Project Config: metaloot.json#

The first deploy writes a metaloot.json next to your package.json. Commit it — it pins which game future deploys update:

metaloot.json
{
  "gameId": "…",
  "slug": "my-game",
  "name": "My Game",
  "outDir": "dist"
}

Your Game's Domain#

The game's slug (lowercased, a–z 0–9 -, max 40 chars) becomes the subdomain: https://<slug>.metaloot.app. Alongside your files, the platform serves these routes on the same origin:

/auth/metaloot/start · /callback · /session · /logoutSign in with Metaloot, provisioned per game — see Authentication. A sign-in widget is injected automatically; opt out with <meta name="metaloot-auth-widget" content="off" />.
wss://…/mp/rooms/<roomId>Multiplayer rooms on Cloudflare Durable Objects — see Multiplayer. GET /mp reports availability and versions.
/__metaloot/multiplayer.jsThe zero-install multiplayer client module, versioned with the platform.
/__metaloot/auth-widget.jsThe injected sign-in widget (shadow-root, unstyled by your CSS).
/__metaloot/assets/<id-or-slug>.glbSame-origin, edge-cached proxy for public Studio assets — see Assets.

Caching & SPA Routing#

  • Hashed files under assets/ (standard bundler output) are cached immutably at the edge.
  • HTML is served with no-cache, so a new deploy is visible immediately.
  • Unknown paths fall back to index.html — SPA routing works with no configuration.

Deploy Limits#

5,000 filesMaximum files per deploy.
1 GiBMaximum total size per deploy.
512 MiBMaximum size for a single file.
30 minutesPresigned upload URLs expire; the CLI finishes well within this.
index.htmlRequired at the root of the deployed folder.
Need CI deploys? Create an API token with the deployments:write scope and set it as METALOOT_TOKEN in your pipeline — see API Tokens.

Under the Hood#

Sites are stored in Cloudflare R2 and served by a Worker matched on *.metaloot.app. Uploads land in a per-deploy prefix; finalize flips a pointer in the site's config, which is why deploys are atomic and rollback-safe. Multiplayer rooms are SQLite-backed Durable Objects colocated with the hosting, and the per-site OAuth credentials that power auth and multiplayer never leave the server side.