Using DataStore, you can save and load essential player data such as level, experience points, and gold. This allows you to maintain the player's progress consistently, enabling the development of games with progression elements such as RPGs.
How to Use
Supported Data Types
Data Type
Support Status
number
O
string
O
bool
O
table
O
object
Not supported
함수
Not supported
Basic Structure
You can use GetDataStore from the DataStoreService to retrieve a DataStore object with a specified name. Data can then be saved to or loaded from the DataStore object using a Key-Value format.
Key: A unique name that identifies the data (e.g., PlayerGold)
Value: The data to be stored (e.g., 1000)
Function
Description
GetDataStore(name)
Retrieve a DataStore object by name
GetAsync(key)
Load data using a key from the DataStore
SetAsync(key, value)
Save data to a key in the DataStore (overwrite)
Get DataStore
local DataStoreService = game:GetService("DataStoreService")
local GoldStore = DataStoreService:GetDataStore("PlayerGold")
Save
local function SaveData(player)
local success, errorMessage = pcall(function()
local saveValue = 1
-- Key : PlayerName / Value : SaveValue
GoldStore:SetAsync(player.UserId, saveValue)
end)
if not success then
print("errorMessage : ", errorMessage)
end
end
Load
local function LoadData(player)
local success, errorMessageOrLoadValue = pcall(function()
-- Key : PlayerName
return GoldStore:GetAsync(player.UserId)
end)
if not success then
print("errorMessage : ", errorMessageOrLoadValue)
else
local loadValue = errorMessageOrLoadValue
print(player.Name, "Load PlayerGold : ", loadValue)
end
end
Full Code Example
The following code loads a player's data from the server when they join the game. If no saved data is found, it sets default values and assigns them to the player's Attributes.
Later, when the save function is called, the current values stored in the Attributes are saved back to the server.
DataManager = {}
local Players = game:GetService("Players")
local DataStoreService = game:GetService("DataStoreService")
-- Define various data types to be saved or loaded
local PlayerData =
{
{ Name = "PlayerGold", InitValue = 0, Store = nil },
}
for i = 1, #PlayerData do
PlayerData[i].Store = DataStoreService:GetDataStore(PlayerData[i].Name)
end
--------------------------------------------------------
-- Save the current value to the server
function DataManager:SavePlayerData(player)
repeat wait() until player:GetAttribute("IsDataLoaded")
print(player, "> SavePlayerData")
local text = ">>>> Save : "
for i = 1, #PlayerData do
local playerData = PlayerData[i]
local store = playerData.Store
local success, errorMessageOrLoadValue = pcall(function()
-- Read the player's Attribute value and save it to the server
local currentValue = player:GetAttribute(playerData.Name)
store:SetAsync(player.UserId, currentValue)
return currentValue
end)
if not success then
text = text .. "errorMessage : " .. errorMessageOrLoadValue
else
local loadValue = errorMessageOrLoadValue
if i > 1 then
text = text .. ", "
end
text = text .. player.Name .. " / Save " .. playerData.Name .. " : " .. tostring(loadValue)
end
end
print(player, text)
end
-- Automatically save when the player leaves the game
Players.PlayerRemoving:Connect(function(player) DataManager:SavePlayerData(player) end)
--------------------------------------------------------
-- Load the value stored on the server
function DataManager:LoadPlayerData(player)
print(player, "> LoadPlayerData")
local text = ">>>> Load : "
for i = 1, #PlayerData do
local playerData = PlayerData[i]
local store = playerData.Store
local success, errorMessageOrLoadValue = pcall(function()
return store:GetAsync(player.UserId)
end)
if not success then
text = text .. "errorMessage : " .. errorMessageOrLoadValue
else
local loadValue = errorMessageOrLoadValue
-- If no saved value exists, set an initial value (InitValue) and save it to the server
if loadValue == nil then
loadValue = playerData.InitValue
store:SetAsync(player.UserId, loadValue)
end
-- Assign the loaded value to the player's Attribute
player:SetAttribute(playerData.Name, loadValue)
if i > 1 then
text = text .. ", "
end
text = text .. player.Name .. " / Load " .. playerData.Name .. " : " .. tostring(loadValue)
end
end
player:SetAttribute("IsDataLoaded", true)
print(player, text)
end
--------------------------------------------------------
-- Load data when the player joins the game
local function LoadPlayerDataWhenEnter(player)
local function onAddCharacter(character)
print(player.Name .. " LoadPlayerDataWhenEnter")
DataManager:LoadPlayerData(player)
end
player.CharacterAdded:Connect(onAddCharacter)
end
Players.PlayerAdded:Connect(LoadPlayerDataWhenEnter)
--------------------------------------------------------
-- Data Loading Example
local function LoadExample(player)
DataManager:LoadPlayerData(player)
end
-- Data Saving Example
local function SaveExample(player)
-- Example code for modifying values before saving
for i = 1, #PlayerData do
local playerData = PlayerData[i]
local currentValue = player:GetAttribute(playerData.Name)
if currentValue ~= nil then
local newValue = currentValue + 1
player:SetAttribute(playerData.Name, newValue)
end
end
DataManager:SavePlayerData(player)
end
LoadPlayerDataWhenEnter(player)
Called when the player joins the game
DataManager:LoadPlayerData(player)
Loads the player's saved data from the server using GetAsync
If no saved data exists, sets an initial value (InitValue) and saves it to the server
Assigns the loaded value to the player's Attribute
DataManager:SavePlayerData(player)
Reads the player's Attribute value and saves it to the server using SetAsync
Automatically saves when the player leaves the game using the PlayerRemoving event
Usage Example
When saving or loading data using DataStore, the way you define the Key determines whether you're managing individual player data or global game data.
For example, if you use a key like RaceGameLeaderBoard instead of Player.Name, you can manage ranking information stored on the server rather than a specific player's data.
Using this approach, you can store and load global game data such as leaderboards, event progress, or server configurations.
Differences Between Published and Test Environments
After publishing, data is saved to and loaded from the actual server in mobile environments.
In contrast, within the Studio test environment, data is temporarily stored locally, and it is automatically deleted when Studio is closed.
Precautions
If the player proceeds with gameplay before data loading is complete, errors may occur. Be sure to display a loading UI until the loading process finishes.
Design the data to be as small and simple as possible.
Excessive requests can lead to data saving failures, so avoid saving repeatedly within a short period.
API calls must not exceed 150 per minute. If this limit is exceeded, the server may impose restrictions.
Since data can be lost due to unexpected game shutdowns or server crashes, make sure to save data periodically.
As saving or loading can fail, use pcall to handle errors and implement retry logic when necessary.