Roblox data store script: save player data
Save coins, levels and progress between sessions — a complete DataStoreService script that won't wipe a player's data when Roblox has a hiccup.
ScriptUpdated November 2, 2026
Where to put it
Script — ServerScriptService > PlayerData (Script). It runs on the server, so players can't change what it does.
- Publish the place, then in Studio open File → Experience Settings → Security and turn on Enable Studio Access to API Services (Roblox recommends a test copy for this).
- Insert a Script into ServerScriptService and paste the code. It creates leaderstats too, so remove any other leaderstats script.
The script
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
local store = DataStoreService:GetDataStore("PlayerData_v1")
local DEFAULTS = { Coins = 0, Level = 1 }
local function onPlayerAdded(player)
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
for name, default in DEFAULTS do
local value = Instance.new("IntValue")
value.Name = name
value.Value = default
value.Parent = leaderstats
end
local ok, saved = pcall(function()
return store:GetAsync("player_" .. player.UserId)
end)
if not ok then
-- Loading failed: don't save over the real data later.
warn("Load failed for", player.Name, saved)
return
end
if type(saved) == "table" then
for name in DEFAULTS do
if type(saved[name]) == "number" then
leaderstats[name].Value = saved[name]
end
end
end
player:SetAttribute("DataLoaded", true)
end
local function save(player)
if not player:GetAttribute("DataLoaded") then return end
local data = {}
for name in DEFAULTS do
data[name] = player.leaderstats[name].Value
end
local ok, err = pcall(function()
store:SetAsync("player_" .. player.UserId, data)
end)
if not ok then
warn("Save failed for", player.Name, err)
end
end
Players.PlayerAdded:Connect(onPlayerAdded)
for _, player in Players:GetPlayers() do
task.spawn(onPlayerAdded, player)
end
Players.PlayerRemoving:Connect(save)
game:BindToClose(function()
for _, player in Players:GetPlayers() do
task.spawn(save, player)
end
task.wait(3) -- give the saves time to finish
end)How it works
- Each player's data is one table saved under the key
player_<UserId>. pcallcatches errors: data store calls can fail when Roblox's servers are busy.DataLoadedstops the script from saving default values over real data when loading failed.BindToClosesaves everyone when a server shuts down, whichPlayerRemovingalone can miss.
Variations
Autosave every few minutes
Protects progress if a server crashes. Add this at the bottom of the script.
task.spawn(function()
while true do
task.wait(180)
for _, player in Players:GetPlayers() do
task.spawn(save, player)
end
end
end)Adding a new stat later
Add it to DEFAULTS. Players with old saves get the default value, and it starts saving from then on — no reset needed.
Common mistakes
- Testing in an unpublished place or without API access — saving silently fails and Output shows a warning.
- Saving on every coin pickup. Data stores have request limits; save on leave, on shutdown and on a timer.
- Renaming the data store (
PlayerData_v1) after launch — players lose access to their old data.
FAQ
Why is my Roblox data store not saving?
The place must be published, Studio needs Enable Studio Access to API Services turned on, and the code must run in a server Script. Check Output for warnings.
Should I use SetAsync or UpdateAsync?
SetAsync is fine for one server saving one player's own data, as here. Use UpdateAsync when several servers might write the same key, such as trading or shared data.
Does data save in Studio?
Only with API access turned on, and it then writes to the real data store. Roblox recommends using a separate test place for that.