ProfileService IS STABLE, BUT NO LONGER SUPPORTED - USE “ProfileStore” FOR NEW PROJECTS - Click for more info
Mad Studio cross-promo:
Check out ReplicaService for state replication / networking!
 If you’re curious about how Madwork is written, give MadLife - code_guidebook a read!
Consider donating R$ to the creator of ProfileService (Click here) if you find this resource helpful!
Madwork - ProfileService
ProfileService is a stand-alone ModuleScript that specialises in loading and auto-saving
 DataStore profiles.
It’s documented:
 ProfileService wiki
It’s open source:
 Roblox library
Watch while you eat a pizza completely healthy meal on the couch - YouTube tutorials:
 Thorough ProfileService tutorial by @M_nzter
 ProfileService in 10 minutes by @CheekySquid
 ProfileService tutorial playlist by @okeanskiy
 Session-locking explained and savable leaderstats by @EncodedLua
 (Will add new tutorials as they come)
A DataStore Profile (Later referred to as just Profile) is a set of data which is meant to be loaded up
 only once inside a Roblox server and then written to and read from locally on that server
 (With no delays associated with talking with the DataStore every time data changes) whilst being
 periodically auto-saved and saved immediately once after the server finishes working with the Profile.
The benefits of using ProfileService for your game’s profiles are:
-  This is my personal module that I intensively support - any bugs you find are also my bugs - In the very unlikely (astronomically unlikely  ) case you do find a bug I’ll usually fix it in around 2 - 3 days if you can give me a decent report. ) case you do find a bug I’ll usually fix it in around 2 - 3 days if you can give me a decent report.
-  Easy to learn, and eventually forget - ProfileService does not give you any data getter or setter functions. It gives you the freedom to write your own data interface. 
-  Built for massive scalability - low resource footprint, no excessive type checking. Great for 100+ player servers. ProfileService automatically spreads the DataStore API calls evenly within the auto-save loop timeframe. 
-  Already does the things you wouldn’t dare script yourself (but should) - session-locking is essential to keeping your data protected from multiple server editing - this is a potential cause of item loss or item duplication loopholes. ProfileService offers a very comprehensive and short API for handling session-locking yourself or just letting ProfileService do it automatically for you. 
-  Future-proof - with features like MetaTagsandGlobalUpdates, you will always be able to add new functionality to your profiles without headaches.
-  Made for ambitious projects - ProfileService is a profile object abstraction detached from the Playerinstance - this allows the developer to create profiles for entities other than players, such as: group-owned houses, savable multiplayer game instances, etc.
ProfileService is part of the Madwork framework
 Developed by loleris
Example code:
-- 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 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 -- 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)ProfileService is server-side only - you’ll need replication code to pass Profile.Data to clients. ReplicaService was designed for this job!
