One of the most important features in any Roblox game is the ability to save player progress. Whether it’s coins, levels, or inventory items, players expect their hard work to be there when they return. In this tutorial, we’ll learn how to use DataStores to save player data safely and reliably.
What Are DataStores?
DataStores are Roblox’s built-in cloud storage system. They let you save data for each player that persists even after they leave your game. Think of it like a filing cabinet in the cloud—each player gets their own folder where you can store their information.
DataStores are free to use and automatically handle the complicated parts of cloud storage for you. However, they do have limits on how often you can read and write data, which is why we need to use them carefully.
Setting Up Your First DataStore
Before we can save anything, we need to get access to the DataStore service and create a DataStore. This code should go in a Script (not a LocalScript) inside ServerScriptService:
local DataStoreService = game:GetService("DataStoreService")
local playerData = DataStoreService:GetDataStore("PlayerData")
local Players = game:GetService("Players")
The string “PlayerData” is the name of our DataStore. You can name it anything you want, but choose something descriptive. If you change this name later, you’ll create a completely new DataStore (the old data won’t transfer automatically).
Loading Player Data When They Join
When a player joins your game, we want to load their saved data. If they’re new, we’ll give them default starting values. Here’s how:
local DEFAULT_DATA = {
Coins = 0,
Level = 1,
Experience = 0
}
Players.PlayerAdded:Connect(function(player)
local success, data = pcall(function()
return playerData:GetAsync(player.UserId)
end)
local playerStats
if success then
if data then
-- Player has saved data
playerStats = data
else
-- New player, use defaults
playerStats = DEFAULT_DATA
end
else
-- Error occurred, use defaults to let them play
warn("Failed to load data for " .. player.Name)
playerStats = DEFAULT_DATA
end
-- Store data in the player for easy access
local leaderstats = Instance.new("Folder")
leaderstats.Name = "leaderstats"
leaderstats.Parent = player
local coins = Instance.new("IntValue")
coins.Name = "Coins"
coins.Value = playerStats.Coins
coins.Parent = leaderstats
end)
Why Use pcall?
You’ll notice we wrapped the GetAsync call in a pcall. This is extremely important. DataStore requests can fail for many reasons: internet issues, Roblox servers being busy, or rate limits. Without pcall, your entire script would crash when an error occurs. With pcall, we catch the error and give the player default values so they can still play.
Saving Player Data When They Leave
Now we need to save the player’s data when they leave. This also goes in the same script:
Players.PlayerRemoving:Connect(function(player)
local leaderstats = player:FindFirstChild("leaderstats")
if not leaderstats then return end
local dataToSave = {
Coins = leaderstats.Coins.Value,
Level = 1, -- You can add more stats here
Experience = 0
}
local success, errorMessage = pcall(function()
playerData:SetAsync(player.UserId, dataToSave)
end)
if success then
print("Data saved for " .. player.Name)
else
warn("Failed to save data for " .. player.Name .. ": " .. errorMessage)
end
end)
Why Use UserId as the Key?
We use player.UserId instead of player.Name because usernames can change, but a player’s UserId never changes. This ensures players never lose their data if they change their username.
Important Best Practices
- Always use pcall around DataStore methods—they can fail!
- Never save data too frequently—you’ll hit rate limits. Only save when necessary (like when players leave).
- Test with Studio’s Data Store emulation enabled, but remember it doesn’t perfectly replicate live conditions.
- Have default values ready so new players or players with loading errors can still play.
- Use UserId, not Name to identify players.
Recap and Next Steps
Congratulations! You’ve learned how to implement a basic but solid data saving system. You now know how to load data when players join, save it when they leave, and handle errors gracefully with pcall.
Here’s what we covered:
- What DataStores are and why they’re important
- How to load player data with proper error handling
- How to save data when players leave
- Best practices to keep your data safe
As your next step, I recommend learning about autosaving (saving periodically while players are in-game) and DataStore2 or ProfileService—community libraries that add extra protection against data loss. Happy scripting!