Organize data by access/update pattern. Split hot, frequently updated state from rarely changed profile, settings, or stats fields.
Public tables are visible to clients through subscriptions. Keep server-only state private and expose derived subsets through views when needed.
Primary keys and unique constraints automatically create indexes; do not add duplicate indexes for them.
Add indexes only for frequent equality, range, subscription, or join paths. Use B-tree by default; direct indexes are for dense unsigned integer keys and are not universally supported in every language.
New columns in existing published tables need defaults and must be appended at the end. Check database migration rules before changing existing schemas.
Auto-increment values are generated by the database and can have gaps after failed transactions.
Use event tables for append-only client notifications; the event flag cannot be changed after publish.
Schedule tables need a ScheduleAt column and a linked scheduled reducer. In TypeScript, import ScheduleAt from spacetimedb, not spacetimedb/server.