Skip to main content

Database Schema

Hyperscape uses PostgreSQL in production and SQLite for local development, with Drizzle ORM for type-safe database access.
Database schema is defined in packages/server/src/database/schema.ts.

Overview


Core Tables

Users

Characters

Skills are stored as individual columns (e.g., smithingLevel, smithingXp) rather than JSONB for efficient querying and indexing.

Inventory

Equipment


Bank System

Bank Storage

Bank Tabs


Persistence & Crash Recovery

Operations Log

The operations_log table provides write-ahead logging for critical operations:
Write-Ahead Log Pattern:
  1. Log operation intent with state
  2. Execute operation
  3. Mark operation complete
  4. On startup, replay any incomplete operations
Use Cases:
  • Trade completions
  • Bank transactions
  • Equipment changes
  • Inventory modifications
Phase 2 Status: The operations_log table and PersistenceService are scaffolding for future integration. They are not currently wired up to TradingSystem or BankSystem.
See Persistence Architecture for complete details on write-ahead logging, transactional saves, and crash recovery.

World Persistence

World Chunks


Player Sessions


Statistics Tables

NPC Kills


Repository Pattern

All database access goes through typed repositories:

Performance Optimizations

Inventory Write Coalescing

The DatabaseSystem uses write coalescing to prevent connection pool starvation during batch operations:
How It Works:
  1. First write executes immediately - No active write for this player, execute directly
  2. Concurrent writes queue - If a write is active, queue the latest snapshot
  3. Latest snapshot wins - New writes replace queued data (only newest matters)
  4. All waiters resolve together - When batch completes, all waiting promises resolve
  5. Recursive drain - After active write completes, drain queued batch if any
Performance Impact: Code Example:
Graceful Shutdown: On DatabaseSystem.destroy(), orphaned waiters are rejected to prevent hanging promises:
This optimization was added in PR #823 to fix “200 pending operations” warnings and game freezes during batch crafting operations like fletching.

Data Types

Timestamps

All timestamps use bigint storing Unix milliseconds for precision:

Positions

Positions use real (float) for sub-tile precision:

IDs

All IDs are text storing UUIDs as strings:

Migrations

Drizzle handles migrations automatically. Run from packages/server/:

Recent Migrations

Migrations are located in packages/server/src/database/migrations/.