If you don’t save user data with ProfileService or DataStore2, then you’re saving data wrongly (unless you’ve taken proper steps to making a secure data store). I wanted to make this tutorial because I had to figure out how to use Profile Service, and it was hard. But in this tutorial, it won’t be, because you’re not figuring this out on your own.
Why can’t I just setup my own data store?
Well, the issue with that is it’ll take up so much valuable time. There’s so much research and experience needed to make your own data store module that you’d have to dedicate months of hard work and research. But if there’s already a FREE resource out there, why not use it? A bunch of big games use it too.
How to write it out
Make a new server script, and paste this code into it:
-- ProfileTemplate table is what empty profiles will default to.
-- Updating the template will not include missing template values
-- in existing player profiles!
local ProfileTemplate = {
Cash = 0,
Items = {},
LogInTimes = 0,
}
----- Loaded Modules -----
local Cache = require(game.ServerScriptService.Cache) --Create a blank module named Cache
local ProfileService = require(game.ServerScriptService.ProfileService)
----- Private Variables -----
local Players = game:GetService("Players")
local ProfileStore = ProfileService.GetProfileStore(
"PlayerData",
ProfileTemplate
)
local Profiles = {} -- [player] = profile
----- Private Functions -----
local function GiveCash(profile, amount)
-- If "Cash" was not defined in the ProfileTemplate at game launch,
-- you will have to perform the following:
if profile.Data.Cash == nil then
profile.Data.Cash = 0
end
-- Increment the "Cash" value:
profile.Data.Cash = profile.Data.Cash + amount
end
local function DoSomethingWithALoadedProfile(player, profile)
profile.Data.LogInTimes = profile.Data.LogInTimes + 1
print(player.Name .. " has logged in " .. tostring(profile.Data.LogInTimes)
.. " time" .. ((profile.Data.LogInTimes > 1) and "s" or ""))
GiveCash(profile, 100)
print(player.Name .. " owns " .. tostring(profile.Data.Cash) .. " now!")
end
local function PlayerAdded(player)
local profile = ProfileStore:LoadProfileAsync("Player_" .. player.UserId)
if profile ~= nil then
profile:AddUserId(player.UserId) -- GDPR compliance
profile:Reconcile() -- Fill in missing variables from ProfileTemplate (optional)
profile:ListenToRelease(function()
Profiles[player] = nil
-- The profile could've been loaded on another Roblox server:
player:Kick()
end)
if player:IsDescendantOf(Players) == true then
Profiles[player] = profile
Cache[player.UserId] = {
data = profile.Data;
}--Other scripts can now access profile data
-- A profile has been successfully loaded:
DoSomethingWithALoadedProfile(player, profile)
else
-- Player left before the profile loaded:
profile:Release()
end
else
-- The profile couldn't be loaded possibly due to other
-- Roblox servers trying to load this profile at the same time:
player:Kick()
end
end
----- Initialize -----
-- In case Players have joined the server earlier than this script ran:
for _, player in ipairs(Players:GetPlayers()) do
task.spawn(PlayerAdded, player)
end
----- Connections -----
Players.PlayerAdded:Connect(PlayerAdded)
Players.PlayerRemoving:Connect(function(player)
local profile = Profiles[player]
if profile ~= nil then
profile:Release()
end
end)
Note, do not remove the comments yet, they’ll help you. Also, go to here if you can’t figure something out or if you need more information:
Save your player data with ProfileService! (DataStore Module) - Resources / Community Resources - DevForum | Roblox
Also, if you already have a data store and there’s important data on it, just check if the player that joined has data with your old data store. If they do, then load that data and paste it into their Profile Service data. After that, just remove their data from the old data store. Eventually, you’ll also be able to remove that code, once enough players have joined of course.
Closing
You might be wondering why I didn’t make a tutorial about DataStore2, and that’s because DataStore2 is older than Profile Service. If you do use DataStore2, you probably don’t need to change to Profile Service. I heard DataStore2 works great, but I prefer Profile Service because its newer.
Edit: 7/21/2025
I edited this post to remove inconventional methods, so that’s why it’s shorter.

