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:
--dirif given, then theoutDirfrommetaloot.json, thendist, thenbuild— each must contain anindex.html. For a plain HTML project, pass--dir .. Use--no-buildto skip your build script. - Dotfiles (except
.well-known),node_modules,.DS_Store, andThumbs.dbare 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 deployProject Config: metaloot.json#
The first deploy writes a metaloot.json next to your package.json. Commit it — it pins which game future deploys update:
{
"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 · /logout | Sign 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.js | The zero-install multiplayer client module, versioned with the platform. |
| /__metaloot/auth-widget.js | The injected sign-in widget (shadow-root, unstyled by your CSS). |
| /__metaloot/assets/<id-or-slug>.glb | Same-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 files | Maximum files per deploy. |
| 1 GiB | Maximum total size per deploy. |
| 512 MiB | Maximum size for a single file. |
| 30 minutes | Presigned upload URLs expire; the CLI finishes well within this. |
| index.html | Required at the root of the deployed folder. |
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.