Start typing to search packages!
geode
By @qvyra
Roblox
Mirrored from WallyGeode
A layered data framework for Roblox. Geode puts DataStoreService, MemoryStoreService and MessagingService behind one API, with guards, reactive data and replication on top.
Geode is in early development. The API will change without notice until 1.0.
Quick start
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Geode = require(ReplicatedStorage.Packages.Geode)
local PlayerData = Geode.players({
name = "PlayerData",
template = { coins = 0, xp = 0, level = 1, inventory = {} },
replicate = { coins = "owner", level = "public" },
})
PlayerData:onLoaded(function(player, profile)
profile:increment("coins", 100)
end)
Each player's data loads when they join and is saved and released when they leave or the server shuts down. Until it loads, PlayerData:get(player) reads the template, and isLoaded, waitFor and onLoaded tell you when the real data is in. In Studio, data stays in memory unless you ask for a separate scope or live data. PlayerData.store is the profile store underneath, with every option visible, for when you need more control.
On the client, the replicated paths arrive as atoms:
local client = Geode.Client.start()
client:atom("coins"):subscribe(function(coins)
print("coins", coins)
end)
Install
With Wally, add Geode to wally.toml and run wally install:
[dependencies]
Geode = "qvyra/geode@0.4.0"
A roblox-ts package is coming. The typings for the whole API already live in types/.
The idea
Polish Geode.players and Geode.setup: player data with the lifecycle handled
Stores Profile, Shared, Ephemeral, Ranked, Matchmaker, plus premades
Primitives scheduler, schema, transactions, leases, guards, bundles, reactions
Adapters DataStore, MemoryStore, MessagingService, remotes, plus mocks
Each layer only uses the public API of the one below it. Start at the top and drop down a level whenever you need more control.
DataStore is always the source of truth. MemoryStore and MessagingService only make things faster or help servers coordinate, and correctness never depends on them. Every write from every source goes through one transaction pipeline, so guards, reactions, replication and history all see the same changes.
What's inside
- Profiles: session locked player data with autosave, fast server hops, migrations, receipts that never grant twice, a mailbox for offline players and erasure on request
- Shared stores: data any server writes, with the whole pipeline run inside UpdateAsync
- MemoryStore: validated hash maps, sorted maps and queues, plus presence, locks with fencing tokens, counters, rate limits and job queues
- Matchmaking and leaderboards: one elected matcher per queue, all-time and windowed boards
- Replication: per path visibility, diffs batched once per frame, client atoms and rate limited remote ops
- History and tooling: version history, rollback through the server holding a profile, an audit log and a telemetry bus
The guides and the API reference are at qvyra.github.io/geode. DECISIONS.md records why things are built the way they are, and example/ holds a small game that uses most of it.
Development
You need Rokit and Node.js.
rokit install
npm ci
lune run check
lune run check runs formatting, linting, type checking and tests, the same as CI. lune run fix applies the formatters. lune run test <filter> runs only the spec files whose path contains the filter. See CONTRIBUTING.md before opening a pull request.
License
MIT, see LICENSE.
Package Details
Install command (Click to copy)
Version
0.4.0
License
MIT
Safe for commercial use
Automated license review — not legal advice.
