PlayerDataStore
Roblox’s Most Advanced Player Datastore Yet Easiest To Use
Roblox has made Database way more complicated than it has to be, not only that but there’s also the possibility of data loss, data corruption, hitting limits, limitations, and a lot of more issues. That’s when modules such as ProfileStore for Datastore gets used to prevent those data issues, however, it still doesn’t address a few issues that the vast majority of Roblox developers struggle with which is that it isn’t easy to use and very complicated. Not only that, it still uses an outdated system ‘DataStore’ for session-locking which as a result, reduces your DataStore limits and is also extremely slow. Along with all of that, ProfileStore and most of other modules don’t support Roblox datatypes such as Vector3, Vector2, Color3, CFrame, etc at least not without specifying their types manually.
PlayerDataStore addresses and fixes all of these issues for you.
Contact

.ranu.
Some of the Games that Use it
Overview
What is PlayerDataStore?
PlayerDataStore is Roblox’s easiest to use yet most powerful player-oriented Roblox DataStore System that has all the modern systems to prevent all the possible issues.
It comes with session-locking using MemoryStore, and is the only DataStore System in Roblox with MemoryStore that is prepared for extremely rare scenarios where Roblox MemoryStore fails (which has only happened a couple times in the past, as of today). Just a couple days ago, it took down thousands of games that were using MemoryStore. With this module, that will never happen to you even if MemoryStore fails. It also has auto-retry system in case DataStoreService fails.
It also comes with Default Player Data Template, and has auto-reconciliation.
It is more performant and easier to use than the most popular DataStore system in Roblox ProfileStore
It leaves no chance for Data loss and Data corruption, while it also provides all the features that you’d realistically need in a Datastore System.
It supports reading/updating data to both Offline and Online players, meaning whether they are in your game server or not, it will be able to work smoothly even if they are in different servers of your game.
It also uses caching system, and makes the minimum use of MemoryStore & DataStore so your game servers & game limits wouldn’t be reached/throttle. Way less than ProfileService.
The module makes proper and minimum use of DataStore & MemoryStore & MessageService.
It is one of the very few DataStore systems in Roblox that support most of the Roblox datatypes such as CFrame, Ray, Vector3, Vector2, Vector3int16, Vector2int16, Color3, NumberSequence, and a lot more without you even having to specify their types.
It comes with a serializer and also comes without the JSON overhead at the fastest speed possible.
It is also highly configurable, has autosave, has configs to enable/disable serializer, separating Studio/Client datastore/session-lock, feature to pretend to be a new user playing your game for first time, and a lot more.
Most of its methods accept player instance, player userid as number, string because we know that a lot of developers suffer from giving the wrong types of datatypes, for example instead of giving userid as a number, they give it as a string. This handles all of that for you smoothly.
Most methods yield such as :SetValue, :GetValue, :GetData, etc if they are in the server, with a timeout automatically, so you don’t even have to worry about their data initializing at first when they join.
The module comes with auto-correct for the default player data template.
It has Erase User data method and is GDPR compliant.
It also has a bit of tutorial and full documentation in it.
Also, Automatically checks for updates.
API
Functions:
1. GetData(player: Player): table? [comes with Reference]
- Returns the full data table for the player.
- Returns nil if data is not loaded.
2. GetValue(player: Player, ...: string): (any, boolean) [can come with Reference]
- Returns the value for a specific key in the player's data.
- Returns nil if data not loaded or key doesn't exist.
- Second return value is false if the player's data wasn't loaded, otherwise true.
# Recommended to Use Instead #
GetOfflineValue = FetchValue
2.5. FetchValue(player: Player | number | string, ...: string): any [can come with Reference]
- Retrieves a nested value from a player's offline data.
- If they are online in the server, then it will use their current cached data from the server.
- Accepts a Player instance, userId (number), or userId (string).
- If the player is currently online, falls back to GetValue.
- Returns nil if data is missing or the key path does not exist.
3. SetValue(player: Player | number | string, ...: any)
- Sets a nested value inside the player's session data or offline data using a variable number of keys.
- The first argument can be a Player instance, a userId number, or a userId string.
- The following arguments are one or more keys followed by the final value to set.
- If the player is online, waits for their data to load; if data is not loaded, returns early without setting.
- If the player is offline, loads their offline data, applies the nested set, saves the data, and publishes a message for synchronization.
- Returns true on success; otherwise returns nil.
4. UpdateData(player: Player | number | string, changes: table)
- Applies multiple updates to the player's session data or offline data in one call.
- The first argument can be a Player instance, a userId number, or a userId string.
- The second argument is a table of key/value pairs representing updates.
- Nested tables are supported, and will automatically create intermediate tables if they do not exist.
- If the player is online, waits for their data to load and applies all changes in memory.
- If the player is offline, loads their offline data, applies all changes, saves the data once,
and publishes a "BulkUpdate" message for synchronization.
- Returns true if all updates were successfully applied; otherwise returns false.
5. Increment(player: Player | number | string, ...: any) -- returns true if succeeded
- Increments a nested numeric key by the specified amount.
- Initializes missing nested structure and key to 0 if needed.
- Supports both online and offline data (if OfflineModeEnabled).
- Does nothing if data is not loaded or unavailable.
- Returns true on success; otherwise returns nil.
6. HasData(player: Player): boolean
- Returns true if player data is loaded in session cache, else false.
7. RemoveKey(player: Player | number | string, ...: any) -- returns true if succeeded
- Removes a specific nested key from the player's data.
- Works for both online and offline players:
• If the player is online and session data is loaded, it modifies sessionData.
• If the player is offline, it loads and updates the offline data file.
- Does nothing if data is not loaded or path is invalid.
- Returns true on success; otherwise returns nil.
8. * GDPR Compliance - Right to Erase User Data:
:EraseUserData(userId: number | string)
>> Advanced From Here <<
* (Advanced) WaitForData(player: Player, timeout: number?): boolean
- Waits for player data to be loaded or timeout (default 15s).
- Returns true if data is loaded and player still in game; false otherwise.
* (Advanced) :Reconcile(player: Player | number | string, data) * (Advanced) :Reconcile(player: Player | number | string, data) : boolean
* (Advanced) :GetDefaultTemplate()
* (Advanced) :_DontSaveOnLeaveForPlayer(player: Player | number | string) : boolean
* (Advanced) Specific Offline Datastore Functions:
:LoadOfflineData(player: Player | number | string) [can come with Reference]
:SaveOfflineData(player: Player | number | string, data: any)
(Online / Offline)
:FetchValue(player: Player | number | string, ...: string): any [can come with Reference]
Usage
It’s the easiest yet the most powerful DataStore module in all of Roblox, just look at how easy it is to use.
Here’s a couple videos of its usage:
Offline Data Modification Example
local OfflineLoadedData = PlayerDataStore:LoadOfflineData(3267747943)
print(OfflineLoadedData)
OfflineLoadedData.Hi = {}
OfflineLoadedData.Col = Color3.fromRGB(0, 200, 50)
OfflineLoadedData.Hi3 = false
OfflineLoadedData.Hi4 = 6
OfflineLoadedData.Pos = Vector3.new(1,5,2)
PlayerDataStore:SaveOfflineData(3267747943, OfflineLoadedData)
or even an easier and more efficient way you can just do like this and it will work like magic whether they are online, offline, or in another server of the game:
UpdateData(player, { -- or UpdateData(3267747943, {
Stats = { Kills = 10, Deaths = 3 },
TestStats = { f = 1, t = { b = { n = 1 } } },
Test = true,
N = 2,
Text = "test"
})
As you can see above, it also supports Write to data without necessarily having to use :SetValue, but instead by getting a reference to the cached data and making changes to it which would directly update the cached data.
This can also be done in both online and offline mode, in online mode using GetData or GetValue/GetOfflineValue you can get reference to the cached data.
You also don’t have to worry whether their data was initialized before or not, it safely handles everything for you.
The most special thing about this module is that everything is handled for you, you don’t have to worry about anything. You don’t need to worry about Profiles, initializing Session-locking, clearing cached data, roblox datatypes, specifying datatypes, data loss/corruption, and all other stuff. You just straight get to use it!
Comparison between Usage of ProfileStore and PlayerDataStore
In this comparison, both modules will be achieving the same goal.
ProfileStore Usage Example:
local ProfileStore = require(game.ServerScriptService.ProfileStore)
-- The PROFILE_TEMPLATE table is what new profile "Profile.Data" will default to:
local PROFILE_TEMPLATE = {
Cash = 0,
Items = {},
}
local Players = game:GetService("Players")
local PlayerStore = ProfileStore.New("PlayerStore", PROFILE_TEMPLATE)
local Profiles: {[Player]: typeof(PlayerStore:StartSessionAsync())} = {}
local function PlayerAdded(player)
-- Start a profile session for this player's data:
local profile = PlayerStore:StartSessionAsync(`{player.UserId}`, {
Cancel = function()
return player.Parent ~= Players
end,
})
-- Handling new profile session or failure to start it:
if profile ~= nil then
profile:AddUserId(player.UserId) -- GDPR compliance
profile:Reconcile() -- Fill in missing variables from PROFILE_TEMPLATE (optional)
profile.OnSessionEnd:Connect(function()
Profiles[player] = nil
player:Kick(`Profile session end - Please rejoin`)
end)
if player.Parent == Players then
Profiles[player] = profile
print(`Profile loaded for {player.DisplayName}!`)
-- EXAMPLE: Grant the player 100 coins for joining:
profile.Data.Cash += 100
-- You should set "Cash" in PROFILE_TEMPLATE and use "Profile:Reconcile()",
-- otherwise you'll have to check whether "Data.Cash" is not nil
else
-- The player has left before the profile session started
profile:EndSession()
end
else
-- This condition should only happen when the Roblox server is shutting down
player:Kick(`Profile load fail - Please rejoin`)
end
end
-- In case Players have joined the server earlier than this script ran:
for _, player in Players:GetPlayers() do
task.spawn(PlayerAdded, player)
end
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(function(player)
local profile = Profiles[player]
if profile ~= nil then
profile:EndSession()
end
end)
VS PlayerDataStore:
local PlayerDataStore = require(game.ServerScriptService.PlayerDataStore)
local Players = game:GetService("Players")
--[[ You can use this along with Reconcile, if you don't wanna put it into DefaultData Template Module.
local PROFILE_TEMPLATE = {
Cash = 0,
Items = {},
}
--]]
local function PlayerAdded(player)
-- EXAMPLE: Grant the player 100 coins for joining:
-- PlayerDataStore:Reconcile(player, PROFILE_TEMPLATE)
-- METHOD #1:
PlayerDataStore:Increment(player, "Cash", 100)
--[[
METHOD #2 of doing it:
local PlayerData = PlayerDataStore:GetData(player) -- yields
if PlayerData then
PlayerData.Cash += 100
end
]]
end
-- In case Players have joined the server earlier than this script ran:
for _, player in Players:GetPlayers() do
task.spawn(PlayerAdded, player)
end
Players.PlayerAdded:Connect(PlayerAdded)
PlayerDataStore also supports most of Roblox datatypes such as Vector3, CFrame, Color3 which most of other modules including ProfileStore don’t, and those that do require you to specify their types. With this module, you have to worry about none of that.
Pricing
The module is currently in sale for 10,000 Robux (tax-covered), can be both USD and Robux. (Preferably Robux)
you can also get it for free if you are an organization / renowned studio, if you credit it.
Other Projects: Ro-Photoshop [Fastest Image Editor & Drawing Module] (Parallel)