CyberMax
CyberMax › Answers

A Roblox DataStore save script that never wipes player data

Updated 2026-10-17 · Roblox and game developers · by CyberMax

Short answer

Load with GetAsync inside pcall and retry; if the load fails, kick the player instead of handing out a blank profile. Save with UpdateAsync on leave, every few minutes, and for every player in game:BindToClose. Never save a profile you failed to load: that one rule prevents most lost-save reports.

  1. In Studio, open Game Settings > Security and turn on Enable Studio Access to API Services (needed to test DataStores in Studio).
  2. Put the script in ServerScriptService. Change DEFAULT to your own fields.
  3. Read and change profiles[player] from your other server scripts instead of calling the DataStore directly.
  4. Test: join, change a value, leave, rejoin. Then stop the server with players in it to test BindToClose.

Copy-paste code

ServerScriptService/PlayerData.server.lua

local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local store = DataStoreService:GetDataStore("PlayerData_v1")

local DEFAULT = { coins = 0, level = 1 }
local profiles = {} -- [player] = data, only when the load worked

local function key(player) return "u_" .. player.UserId end

local function load(player)
	for attempt = 1, 3 do
		local ok, data = pcall(store.GetAsync, store, key(player))
		if ok then
			profiles[player] = data or table.clone(DEFAULT)
			return
		end
		task.wait(attempt * 2)
	end
	player:Kick("Your data could not load. Please rejoin.")
end

local function save(player)
	local data = profiles[player]
	if not data then return end -- never write a profile that failed to load
	pcall(store.UpdateAsync, store, key(player), function()
		return data
	end)
end

Players.PlayerAdded:Connect(load)
Players.PlayerRemoving:Connect(function(player)
	save(player)
	profiles[player] = nil
end)

game:BindToClose(function()
	for _, player in Players:GetPlayers() do
		task.spawn(save, player)
	end
	task.wait(3)
end)

task.spawn(function() -- autosave every 3 minutes
	while true do
		task.wait(180)
		for _, player in Players:GetPlayers() do save(player) end
	end
end)

Good to know

Why UpdateAsync instead of SetAsync: UpdateAsync gives you the stored value first, so you can refuse to overwrite newer data (for example, a version number that went backwards). SetAsync writes blindly.

What this script does not do: stop two servers saving the same player at once (a player who rejoins fast can be loaded on server B before server A finished saving). That needs session locking, which is what ProfileService-style modules add.

Studwright: Roblox systems that never lose saves

from $12

Studwright's SaveData adds the session lock this script lacks (one server owns a save at a time), and the kit has 15 more tested modules: Receipts, Codes, DailyRewards, Leaderboard, Inventory, Currency and others.

Secure checkout · 14-day fix-or-refund if it doesn't work as described (terms)

Questions

Why did my player's data reset?

Almost always a failed or slow GetAsync that the script treated as a new player, followed by a save of the blank profile. The guard in save() stops that write.

How often can I save?

Roblox allows 60 + numPlayers × 40 writes per minute per server. A save on leave plus an autosave every 3 minutes uses a tiny part of it.

Do I need DataStore2 or ProfileService?

Not for a small game. You need session locking once players can hop servers quickly, or once losing an item costs real Robux.

Free: the Roblox Starter Kit

7 free Luau modules (damage, pets, shop formatting, admin audit log, tycoon guards and more) plus 3 free calculators, then 5 short emails with the scripting fixes we see go wrong most often.

You get one email to confirm first. Then the kit, and 5 short emails over two weeks. One-click unsubscribe in every email; we never share your address.

Related answers

Roblox DataStore limits: requests per minute, size per key, key namesThe DataStore limits from Roblox's docs: 60 + players × 40 reads and writes a minute, 4 MB per key, 50-charactRoblox leaderboard script: leaderstats you can copy and pasteA working Luau leaderstats script for the player list leaderboard, with coins and level values that save, plusHow to use developer products in Roblox (ProcessReceipt that never double-grants)Sell coins and boosts with developer products: the ProcessReceipt pattern that records each PurchaseId so a pu