Offline messages and edits
Send a gift to a player who is offline with store:message; it is handled exactly once. Edit a
key from a support tool with store:edit, without kicking anyone.
Messages and edits.
KeepBlox keeps session-locked player profiles on DataStore. Only one server can write a profile at a time, and a server that loses the session stops writing at once.
It stores the same record format as ProfileStore and speaks the same lock protocol. That gives you three things:
KeepBlox.Compat.ProfileStore is ProfileStore’s API over KeepBlox. Keys
stay where they are, in the same format.See Migrating from ProfileStore for the details.
Every library below ran unmodified in the same simulator, over seeds 1-20, with the same players and faults. The worst case over all seeds is shown. The benchmarks page has every scenario and the methodology.
| KeepBlox | ProfileStore | ProfileService | |
|---|---|---|---|
| Invariant violations | 0 | 0 | 0 |
| Progress a server crash loses (steps of play) | 4 | 287 | 29 |
| Data store reads per player-hour | 13.1 | 13.6 | 122.0 |
| Data store writes per player-hour | 13.1 | 13.6 | 122.0 |
| Slowest open after a crash (s) | 9.1 | 46.6 | 63.7 |
On Roblox’s real services (the live check) a hand-over took 4.2-4.6 s and a crash takeover 11.6-12.9 s; live calls take 0.3-0.6 s each. A crashed KeepBlox server is known dead within about 9 seconds in the simulator: every server beats in MemoryStore every 4 seconds, and a beat that stands still for two beats means the server is gone. The same beat carries a snapshot of each changed profile (a large one as its edits since it was stored), so a crash loses about one beat of play instead of an autosave interval. How it works explains the mechanism.
local Players = game:GetService("Players")local ServerScriptService = game:GetService("ServerScriptService")local KeepBlox = require(ServerScriptService.KeepBlox)
local store = KeepBlox.store("Profiles", { template = { coins = 0 } })
Players.PlayerAdded:Connect(function(player) local result = store:load(`u_{player.UserId}`, { cancel = function() return player.Parent == nil end, }) if not result.ok then player:Kick(`Your data could not be loaded ({result.reason}). Please rejoin.`) return end result.profile.Data.coins += 10 -- change it in place; KeepBlox saves itend)
Players.PlayerRemoving:Connect(function(player) local profile = store:profiles()[`u_{player.UserId}`] if profile then profile:release() endend)The quick start walks through a complete setup.
Offline messages and edits
Send a gift to a player who is offline with store:message; it is handled exactly once. Edit a
key from a support tool with store:edit, without kicking anyone.
Messages and edits.
Trades
store:trade changes two profiles open on the same server together: both or neither.
Trades.
Shared documents
KeepBlox.shared holds documents no server owns, changed atomically by any server.
Shared documents.
Leaderboards
A number read from each profile, mirrored to an ordered data store and read back with
store:leaderboard. Leaderboards.
Importers
Move from DocumentService, Lapis, DataKeep, DataStore2 or Suphi’s DataStore Module, one key at a time on its first load. Importing.
Purchases
KeepBlox.processReceipt grants a developer product once and never loses it.
Purchases.
Schema and migrations
Describe the data with KeepBlox.schema, and move old data forward with numbered migrations. Give
them a way back and writeVersion, and a release can be rolled back without locking anyone out.
Schema and migrations.
Versions and rollback
List a key’s past versions, read one, and restore it safely. A restore names the purchases it took back, so none is lost quietly. Versions and rollback.
Compression
Profiles over a threshold are stored compressed, so data past the 4 MB limit still saves. Large profiles.
Studio modes
Play tests use the live store, memory only, or a read-only copy of live data. Studio and testing.
Every promise KeepBlox makes is checked by a spec in the repository. Guarantees lists each one with the spec that proves it.