Roblox DataStore: How to Save and Load Player Data
Posted: Sat Oct 17, 2026 7:55 am
Roblox DataStore: How to Save and Load Player Data
If you have ever built a Roblox game where players lose their progress the moment they leave, you have hit the core problem DataStore solves. DataStoreService lets you store data that persists between sessions, like items in a player's inventory or skill points. Without it, everything resets when the player disconnects.[3]
This guide covers the essentials: creating a data store, reading and writing data, handling multiple servers, and saving on disconnect.
Enabling Studio Access
By default, Studio cannot access data stores. You need to enable it before testing. Publish your game, then go to File, Experience Settings, Security, and turn on "Enable Studio Access to API Services." Do not enable this for a live game you do not want to risk, because Studio accesses the same data stores as the client application.[3][4]
Creating a Data Store
Always call DataStoreService from a server-side Script. Roblox blocks all data store access from the client so that only the server can read and write persistent player data. This prevents players from exploiting the game to steal or overwrite each other's data.[4]
Give your data store a unique name to keep things organized. Here is how you create one:[3]
If the data store does not exist yet, Studio creates it the first time you save data to it.[3]
Writing Data with SetAsync
A data store is like a dictionary. A unique key indexes each value. For player data, the key is usually the player's UserId and the value is whatever you want to save.[4]
SetAsync is a network call that can fail. Always wrap it in pcall so your script does not crash when the request drops.[3]
Reading Data with GetAsync
GetAsync returns nil if the key does not exist. Use that to give new players a default value.[3]
SetAsync vs UpdateAsync
SetAsync overwrites the value at a key. It is fast but can cause data inconsistency if two servers try to set the same key at the same time.[3]
UpdateAsync reads the current value before writing, which makes it safe for multi-server scenarios. It is slower because it reads first, but it prevents lost updates when two servers act on the same key simultaneously. Use UpdateAsync when correctness matters more than raw speed.[3]
Saving on PlayerRemoving
Connect to the Players.PlayerRemoving event to save data when a player leaves:[4]
Relying only on PlayerRemoving is risky. If the server crashes or the player disconnects unexpectedly, you lose the latest progress. Add an auto-save loop that writes every few minutes to protect against that.[4]
Storing Player Position
Data stores only accept numbers, strings, booleans, and tables. You cannot save a Vector3 or CFrame directly. Split the position into X, Y, and Z numbers and save them as a table. When loading, rebuild the Vector3 and use PivotTo to move the character back.[4]
Sources
If you have ever built a Roblox game where players lose their progress the moment they leave, you have hit the core problem DataStore solves. DataStoreService lets you store data that persists between sessions, like items in a player's inventory or skill points. Without it, everything resets when the player disconnects.[3]
This guide covers the essentials: creating a data store, reading and writing data, handling multiple servers, and saving on disconnect.
Enabling Studio Access
By default, Studio cannot access data stores. You need to enable it before testing. Publish your game, then go to File, Experience Settings, Security, and turn on "Enable Studio Access to API Services." Do not enable this for a live game you do not want to risk, because Studio accesses the same data stores as the client application.[3][4]
Creating a Data Store
Always call DataStoreService from a server-side Script. Roblox blocks all data store access from the client so that only the server can read and write persistent player data. This prevents players from exploiting the game to steal or overwrite each other's data.[4]
Give your data store a unique name to keep things organized. Here is how you create one:[3]
Code: Select all
local DataStoreService = game:GetService("DataStoreService")
local goldStore = DataStoreService:GetDataStore("PlayerGold")Writing Data with SetAsync
A data store is like a dictionary. A unique key indexes each value. For player data, the key is usually the player's UserId and the value is whatever you want to save.[4]
Code: Select all
local success, err = pcall(function()
goldStore:SetAsync("User_1234", 50)
end)
if not success then
print(err)
endReading Data with GetAsync
Code: Select all
local success, currentGold = pcall(function()
return goldStore:GetAsync("User_1234")
end)
if success then
print(currentGold)
endSetAsync vs UpdateAsync
SetAsync overwrites the value at a key. It is fast but can cause data inconsistency if two servers try to set the same key at the same time.[3]
UpdateAsync reads the current value before writing, which makes it safe for multi-server scenarios. It is slower because it reads first, but it prevents lost updates when two servers act on the same key simultaneously. Use UpdateAsync when correctness matters more than raw speed.[3]
Saving on PlayerRemoving
Connect to the Players.PlayerRemoving event to save data when a player leaves:[4]
Code: Select all
local Players = game:GetService("Players")
Players.PlayerRemoving:Connect(function(player)
local userId = player.UserId
if playerGold[userId] then
saveGold(player, playerGold[userId])
end
end)Storing Player Position
Data stores only accept numbers, strings, booleans, and tables. You cannot save a Vector3 or CFrame directly. Split the position into X, Y, and Z numbers and save them as a table. When loading, rebuild the Vector3 and use PivotTo to move the character back.[4]
Sources