DOCS · SCALING
Scaling & reliability
What is implemented today, what has actually been measured, and what would need extra infrastructure.
NO CAPACITY CLAIMS YET
No load test has been run against WORLD yet, so we do not claim support for any specific number of concurrent players. The 100 / 1,000 / 10,000 user scenarios below are ready to run on a staging copy; results will be published here once measured.
Implemented in the app
- Local movement. Walking renders every frame on your device. Other players see you via live broadcast (~8 updates/s, only when you move). Your saved tile position is written at most every 5 s and only when it changed.
- Versioned world snapshots. Public maps are served from
/api/public/world-snapshot/:id/:revisionwith long-lived immutable caching; any edit bumps the revision and therefore the URL. - Paginated directory. Explore loads 24 worlds per page with "Load more", debounced search and indexed sort columns (newest, trending, featured).
- Database indexes on worlds, chat, visits, sales, ledger, shop items and autosaves for the queries the app actually runs.
- Idempotent purchases. Each shop purchase carries a unique request key. Retrying after a network failure returns the original result instead of charging twice. Balance, stock, inventory, ledger and sale rows change in one database transaction with row locks.
- Rate limits (per account, in the database): purchases 20/min, chat 1/s, error reports 10/min. Editor saves and in-play edits are revision-checked so concurrent edits never overwrite each other.
- Editor autosave stores a snapshot at most every 45 s while there are unsaved changes (last 10 kept); saves compare revisions and keep your local work on conflict.
- Bounded realtime. One channel per world you are in, removed when you leave; the connection no longer restarts after every map edit. Polling intervals were lengthened (player state 20 s, chat 10 s plus instant refresh on chat events, builder access 30 s) and pause in background tabs.
- Retry with backoff. Failed reads retry twice with capped exponential backoff and jitter, avoiding retry storms during outages. Pages and the game view show retry buttons.
- Instrumentation. Browser errors are de-duplicated, throttled and recorded;
/api/public/healthreports database round-trip time; signed-in admins see live counts and top errors at/admin. - Security. Row-level security on every table; credits, quests, pets and purchases change only through server-side functions with input limits; payload sizes for chat, names, quests and maps are bounded.
Architecture
- Pages and server functions run on an edge worker runtime (scales horizontally, managed by hosting).
- One managed Postgres instance holds all durable state; realtime presence/broadcast is provided by the managed realtime service.
- Static assets (scripts, styles, sprites drawn in code) are fingerprinted and cached by the CDN.
Known bottlenecks
- Single database instance. All writes (game actions, chat, purchases) share one Postgres. This is the first limit you will hit.
- Realtime fan-out. Movement broadcast cost grows with players² per world. Busy worlds (50+ people in one map) will need sharding into instances.
- AI creature chat is limited by AI gateway rate limits and usage costs.
- No background job queue. Slow work runs inline today; pruning (autosaves, error logs) happens inside the write that creates them.
Infrastructure that must be provisioned separately
- Bigger database instance — available in backend settings (more CPU/RAM; higher cost). Do this first when database CPU or connections saturate.
- Edge/IP rate limiting & bot protection (e.g. a WAF in front of the custom domain) — not built into the app.
- Redis for hot counters, leaderboards and shared rate limits — only if database rate-limit rows become hot.
- Queue + workers for analytics roll-ups, notifications and future on-chain $WORLD settlement.
- Dedicated realtime servers (authoritative game servers per world shard) if a single world needs hundreds of simultaneous players.
- Read replicas for directory/leaderboard reads at high traffic.
Costs
Hosting and the database are usage-billed. Main cost drivers: database instance size, realtime messages (movement broadcasts), AI creature replies, and bandwidth. Exact prices are shown in your workspace billing — we don't estimate them here.
Load testing
A k6 script in loadtest/world.k6.js runs 100, 1,000 or 10,000 virtual users against health, Explore and world snapshots. It refuses to target the production domain. Run it against a staging copy only, then record p95 latency, error rate and database CPU here.