NexusData
A small, modular Luau data library for Roblox experiences. It wraps DataStoreService in a simpler profile API, while keeping the storage work on the server.
Status: starter library / review before production. Test in a separate Roblox experience with Studio API access enabled before using live player data.
What is included
- Simple profile API with template defaults and schema versions
- Session locking using
UpdateAsync - Autosave and save-on-leave /
BindToClose - Retry with bounded exponential backoff
- Dirty tracking and helpers such as
Set,Get,Update,Increment,ArrayInsert, andArrayRemove - Safe profile release and load failure handling
- Optional ordered stores for leaderboard values
- Typed Luau API surface and examples
Install
Copy src/NexusData into ServerScriptService as a ModuleScript named NexusData, or merge its children into a ModuleScript. The folder layout in this repository is source organization; Roblox ModuleScripts must be arranged to match require paths.
For the easiest setup, create:
ServerScriptService
└── NexusData (ModuleScript) -- contents of src/NexusData/init.lua
├── Config (ModuleScript)
├── Store (ModuleScript)
├── Profile (ModuleScript)
└── Util (ModuleScript)
Adjust requires if you place the files differently.
Enable Game Settings → Security → Enable Studio Access to API Services only in a test place first. Never test against production player data.
Quick start
local Players = game:GetService("Players")
local NexusData = require(game.ServerScriptService.NexusData)
local PlayerStore = NexusData.CreateStore("PlayerData_v1", {
Coins = 0,
Level = 1,
XP = 0,
Inventory = {},
Settings = {
Music = true,
Sensitivity = 1,
},
})
Players.PlayerAdded:Connect(function(player)
local profile, err = PlayerStore:LoadProfileAsync(player.UserId)
if not profile then
player:Kick("Your data could not be loaded. Please rejoin.")
warn(("NexusData load failed for %s: %s"):format(player.Name, tostring(err)))
return
end
profile:Reconcile()
print(profile.Data.Coins)
profile:Increment("Coins", 100)
end)
Players.PlayerRemoving:Connect(function(player)
PlayerStore:ReleaseProfile(player.UserId)
end)
game:BindToClose(function()
PlayerStore:Close()
end)
Before using this in a live game
DataStoreServiceis server-only. Never expose data mutation to the client without server-side validation.- Use
UpdateAsyncfor session ownership and atomic writes. - DataStore calls can fail or be throttled. Do not silently replace a failed load with defaults and continue playing.
- Session locking reduces concurrent edits but no custom data system can promise zero data loss under every platform failure.
- Store keys are strings. Keep store names stable; changing the name creates a new data namespace.
- Do not store Instances, functions, userdata, cyclic tables, or unsupported values.
- DataStore budgets are finite. Tune autosave and payload size for your experience.
- This repository is a foundation, not a substitute for load testing and code review.
Design approach
The public API is intentionally small. Most game scripts should only need to create a store, load a profile, read or update its data, and release it when the player leaves. The internal modules keep storage retries, profile state, and session ownership out of ordinary gameplay code.
This is an early version, not a claim of production-grade data safety. Run it in a separate test experience, simulate failed requests and server shutdowns, and review the session-locking code before trusting it with valuable live data.