Datastore Tutorial for Beginners

I’ve created a tutorial for new people regarding the datastore and how to save multiple/singular data.

In this tutorial I’m gonna try my best to explain every single line assuming that you’re really new to coding, but if you already know some basic stuff, it will be easier to read.

For any improvements for this topic/thread please comment down below so I can improve it and make it better for future readers

Copy code for lazy people

Btw, the tutorial is under this code, this just shows what you’re gonna learn today

-- This for lazy people who just came to copy & paste, not to learn the code...

-- // Assigning variables //
local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("MyDataStore") -- This can be changed to whatever you want

local function saveData(player) -- The functions that saves data
	
	local tableToSave = {
	    player.leaderstats.Money.Value; -- First value from the table
	    player.leaderstats.Coins.Value -- Second value from the table
	}
	
	local success, err = pcall(function()
		dataStore:SetAsync(player.UserId, tableToSave) -- Save the data with the player UserId, and the table we wanna save
	end)
	
	if success then -- If the data has been saved
		print("Data has been saved!")
	else -- Else if the save failed
		print("Data hasn't been saved!")
		warn(err)		
	end
end

game.Players.PlayerAdded:Connect(function(player) -- When a player joins the game
	
-- // Assigning player stats //
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local Money = Instance.new("IntValue")
	Money.Name = "Money"
	Money.Parent = leaderstats
	
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	
	local data -- We will define the data here so we can use it later, this data is the table we saved
	local success, err = pcall(function()

		data = dataStore:GetAsync(player.UserId) -- Get the data from the datastore
		
	end)
	
	if success and data then -- If there were no errors and player loaded the data
		
		Money.Value = data[1] -- Set the money to the first value of the table (data)
		Coins.Value = data[2] -- Set the coins to the second value of the table (data)
		
	else -- The player didn't load in the data, and probably is a new player
		print("The player has no data!") -- The default will be set to 0
	end

end)

game.Players.PlayerRemoving:Connect(function(player) -- When a player leaves
    local success, err  = pcall(function()
	    saveData(player) -- Save the data
    end)

    if success then
        print("Data has been saved")
    else
        print("Data has not been saved!")
    end
end)

game:BindToClose(function() -- When the server shuts down
	for _, player in pairs(game.Players:GetPlayers()) do -- Loop through all the players
		local success, err  = pcall(function()
	         saveData(player) -- Save the data
        end)

        if success then
            print("Data has been saved")
        else
            print("Data has not been saved!")
        end
	end
end)

I know it might look confusing at first, but I will explain each part

Introduction

Introduction:

First of all you need to have API Services Enabled in your game settings.

To Get there, press Home > Game Settings > Security > Check the Enable studio access to api services

Now make a server script (not a local script) and put it into Server Script Service

First we need to define variables, and to do so we will get the DataStoreService and then we will make our own Data Store (trust me it’s not confusing):

local DataStoreService = game:GetService("DataStoreService")
local dataStore = DataStoreService:GetDataStore("MyDataStore") -- You can change the name of the datastore to whatever you want

BE AWARE THAT WHENEVER YOU CHANGE THE DATASTORE IN THE FUTURE NAME IT WILL CREATE A NEW ONE WITHOUT ANY DATA!

After you’re done with this, make sure you save the game and publish it.

Part1 - Assigning the function
local function saveData(player) -- The functions that saves data
	
	local tableToSave = {
	    player.leaderstats.Money.Value, -- First value from the table
	    player.leaderstats.Coins.Value -- Second value from the table
	}
	
	local success, err = pcall(function()
		dataStore:SetAsync(player.UserId, tableToSave) -- Save the data with the player UserId, and the table we wanna save
	end)
	
	if success then
		print("Data has been saved!")
	else
		print("Data hasn't been saved!")
		warn(err)		
	end
end

In here, we are determining the table that we want to save (tableToSave) and inside we are putting the data that you want to save,

So basically – player.leaderstats.Money.Value is gonna insert the players Money.Value into the table, same with Coins, and you can add as much stuff here as you want.

If you don’t know how we got the player, i will tell you later

Now we will use our dataStore (which i assigned at the beginning of the entire script) to save the table, so we do dataStore:SetAsync, Now SetAsync is a built in function that allows us to call the dataStore and tell it that we want to save something, in our case the “tableToSave”, So i say

dataStore:SetAsync(player.UserId, tableToSave)

The “player.UserId” is the key, aka. We want to save the table with the players Id as the unique key, following it with the table we want to save…

For example, when we want to load the players data we will use the key to access their data, like a chest, and it will be player.UserId in our case, a lot of people also do
local key = player.UserId.."-uniqueKey" -- but this is completely optional

Now you might have realized this is all a function with a passing variable saveData(player) – “player” and we never called the function which i will tell you in part 2 and 3

But before that we first need to use a pcall function to make sure the script doesn’t find an error.

Pcall is basically a built in function you can tell it anything and if it catches an error it will not stop the entire script outside the pcall.

So to use a pcall we would do

local success, err = pcall(function()
    -- Do stuff
end)

If the “Do stuff” didn’t get any errors the success is going to be true, meanwhile the error being nil, and if finds an error success will be nil and error will be true

so we can do:

local success, err = pcall(function()
    dataStore:SetAsync(player.UserId, tableToSave)
end)

And if the data got saved we can check if success then:

if success then -- If the data got saved
    print("Data has been saved")
else -- Else if the data didn't get saved
    print("Data has not been saved!")
end

So at the end it all looks like:

local function saveData(player) -- The functions that saves data
	
	local tableToSave = {
	    player.leaderstats.Money.Value, -- First value from the table
	    player.leaderstats.Coins.Value -- Second value from the table
	}
	
	local success, err = pcall(function()
		dataStore:SetAsync(player.UserId, tableToSave) -- Save the data with the player UserId, and the table we wanna save
	end)
	
	if success then
		print("Data has been saved!")
	else
		print("Data hasn't been saved!")
		warn(err)		
	end
end
Part2 - Saving the Data
game.Players.PlayerRemoving:Connect(function(player) -- When a player leaves the game
    saveData(player) -- Save the data
end)

game:BindToClose(function() -- When the server shuts down
	for _, player in pairs(game.Players:GetPlayers()) do
        saveData(player) -- Save the data
    end)
end)

Now that we have the function, we need to call it. So when the player leaves the server, we call the function.

And when we connect the function to player Removing we have to add a variable called player here

game.Players.PlayerRemoving:Connect(function(player) -- this one, it gets the player that left

end) 

and then in the playerRemoving we call the function saveData() and inside the brackets we give it the variable player we got from the line above so it looks like this saveData(player)…

game.Players.PlayerRemoving:Connect(function(player) -- When a player leaves
	saveData(player) -- Save the data
end)

Bind To Close Explanation →
Whenever a player leaves a server (the last player) the data will save then a few seconds later the server shutdowns.

However in roblox studio the server shuts down as soon as the player presses the stop button giving it no time to save the data. (BindToClose is also useful for unexpected shutdowns by roblox)

So what we do to save data in roblox studio is use game:BindToClose()

in our case, when the game is closing we wanna loop through all players and save their data like this

game:BindToClose(function()
	for _, player in pairs(game.Players:GetPlayers()) do -- Loop through all the players
		-- Do stuff
	end
end)
local table = {a, b, c}
for index, value in pairs(table) do -- you can call index, value whatever you want
   print(index)
   print(value)
end

--[[ Output should be
      1, a
      2, b
      3, c
--]]

The game.Players:GetPlayers() will return a table of all players in the game, and for _, player in pairs(playerTable) thats really what it is in short

Most people use i, v. But to look clean I use _, player

So then we wanna do the same thing as for when the player leaves, we save their data by calling the function and giving it the parameter (player).

game:BindToClose(function() -- When the server shuts down
	for _, player in pairs(game.Players:GetPlayers()) do -- Loop through all the players
	    saveData(player) -- Save the data
        end
end)
Part3 - Getting the Data
game.Players.PlayerAdded:Connect(function(player)
	
	local leaderstats = Instance.new("Folder")
	leaderstats.Name = "leaderstats"
	leaderstats.Parent = player
	
	local Money = Instance.new("IntValue")
	Money.Name = "Money"
	Money.Parent = leaderstats
	
	local Coins = Instance.new("IntValue")
	Coins.Name = "Coins"
	Coins.Parent = leaderstats
	
	local data
	local success, err = pcall(function()
		
		data = dataStore:GetAsync(player.UserId)
		
	end)
	
	if success and data then
		
		Money.Value = data[1]
		Coins.Value = data[2]
		
	else
		print("The player has no data!") -- The default will be set to 0	
	end
	
end)

This is the playerAdded part of the script, this is the place where we manage the leaderstats, aswell as the data, so the first few lines are just making the Coins and Money values and inserting them into the player, before loading the data…

However the 2nd part of the script is receiving the data from the table.

So to receive data from the player we can just use

local data

data = dataStore:GetAsync(player.UserId)

But there’s 1 issue, if the player is new it never had any data saved it will error since theres no information about that player in our datastore, so we will use the pcall()

local data -- We are assigning this here so we can use it later on
local success, err = pcall(function()
		
	data = dataStore:GetAsync(player.UserId)
		
end)

The GetAsync is a built in function just as SetAsync, and we are calling the dataStore and telling it to give us the data with the player.UserId being the unique key.

So when we combine all of this it should look like this:

local success, err = pcall(function()
		
	data = dataStore:GetAsync(player.UserId)
		
end)

if success then	
	Money.Value = data[1]
	Coins.Value = data[2]
	
else
	print("The player has no data!") -- The default will be set to 0	
end

Ok, if you’re probably confused by the

Money.Value = data[1]

Whenever we have a table and value inside of it, we can access each and every single value by doing:

local table = {
    "a", -- This is the first value (1)
    "b", -- This is the second value (2)
    "c" -- This is the third value (3)
}

local firstValue = table[1]
print(firstValue)

-- OUTPUT:

-- a

So that line of code is getting the first value from the table because “a” is represented as the first one, the “b” in out example would be 2 and for “c”, the number would be 3.

So at the end the Money.Value is going to be the data[1] and Coins.Value is going to be data[2] as Money is the 1st value in the tableToSave and Coins it’s the 2nd value in the table.

After all of this we will type else (because if the pcall catches an error we wouldn’t get any data and the success will be nil) and then we print that the player has no data and if you want to set a custom data for new players you can do

if success then	
	Money.Value = data[1]
	Coins.Value = data[2]
else
	print("The player has no data!") -- The default will be set to 0	
        -- Custom Change (optional)
        Money.Value = 50
        Coins.Value = 30
end

Manually changing the data in the datastore

After you’ve done everything, you might come to a scenario where you wanna change players saves (for example you can use data stores to ban people and sometimes you wanna unban them by changing their data)

To do this simply, you should get this plugin, It’s safe and it really helps out, I personally use it whenever I wanna change something manually.

When you get the plugin and run it you will be shown a gui with alot of text boxes

It will ask for a Name, Place id should be set automatically and for the Name set it to whatever you’ve called the datastore you wanna manually change data on

After you’ve done that, press Connect.

Then you will be asked to write a key, Now remember the unique key I was talking about, and how you set the unique key to be the players userId, Just write in the players userId you wanna change data on,

For example if I wanna change data for myself I would type my UserId and then press Enter.

After that it will show everything you’ve saved with that User Id on that datastore and you can manually change it.

Here’s a little challenge now. If you read through all 4 parts, I want you to look at the entire script at the top of the topic and see how easy everything is! Good Luck! (Oh also don’t forget to save and publish your work!)

This topic took me a while to write so please if it helped you, I would appreciate it if you dropped a like…

I hope I helped you guys understand this way better, for any questions just ask me!

Note:
You might see comments about some stuff, that I probably deleted/corrected, so no need to worry about that

PS. If you have any way of making this topic better for new readers just leave it in the comments!

563 Likes
Using SetAsync() On a Table error
How to prevent exploits
You need to use BindToClose when using DataStoreService
How to check for data
Best way to Store players XP data
How To Make A Datastore?
Datastorage issues
How to do datastore
Data store script?
How can i make a code system like the video below?
How do I save / load values in a table by using DataStoreService?
How to use datastores to ban people?
How to save data from a shop gui
How to make a Save Data System for Tycoon Game?
How do you save things inside of folder
Saving a players backpack
I need help giving a player speed when a tool is clicked
Not sure how to datastore a model
Saving Skin Color
Trying to save a lot of bool values at a time. But it's crashing
Data Store, Saving Folders and Values
Locker, gui that saves
How to make a saved global variable?
Saving cash and rebirths
Data Store Script Needed
Requires your help to make Techno Studio's Armor system work (the video of it was uploaded 2 months ago..)
How to save a string value?
Error loading a new players Data
How to let players save OC's with a custom character?
Logic error loading and saving datastore values
I don't know how to fix the script
Calling functions when joining/leaving
Help with Datastores (No Leaderboard)
Stats not saving
Datastore Won't Save Value [HELP]
Is normal datastore enough? If not, could anyone give me a good guide on datastore2?
Datastore recieving false values no matter what
Making a DataStore
How to learn DataStorage etc?
Stats don't save when reducing your stats
How to create a datastore?
Quick Data store question
How to make autosave an option?
Level system don't work
Free helpful softwares and tools for all developers!
How to make a Twitter-code system
I Am Having An Issue When It Comes To Sorting Multiple Data For DataStores
Tips / Help on saving multiple data
Need help saving multiple values in one datastore
Doesn’t save data when you log into the game again
Inventory Datastore
Data store isnt saving and/or loading to storage
How do I use datastores to keep track of how many points a player has
Soloved by Kaid
Kills/Deaths on player list
Favorite Music System (Saving Issue)
Reset tycoon when a player leaves the game
How do I store these IntValues to DataStore2?
Sometimes the IPA request is failing for a player that joins the game. Can someone tell how to fix this?
Organized Payer Data
Datastores are not working
Datastore wipe when you join the game, players will be angry if not fixed

Hi there,

I really like the tutorial. I have learnt things I have been doing wrong in my datastore code such not checking if user already had data, using BindToClose() for whenever the server shuts down and data needs to be saved and storing data in arrays.

I have got a few tips for you that you may want to consider using for your next datastore code.

I usually prefer wrapping the while loop in a coroutine so I can continue on writing other player added event code after it without having to worry about data saving. That’s just optional, though I always prefer adding it to prevent using too many scripts in my game and causing confusion or using up memory.
Using SetAsync() replaces the old value to a new value. I have read a post mentioning using UpdateAsync() puts less strain on the Lua code and is more efficient on data saving for your game.
We got a wonderful post made by ForeverHD explaining on why to not use SetAsync()

Although using SetAsync() is still proper, it would propertiese better practice on using UpdateAsync() for saving player data.

Anyways, keep up with the great tutorial. I’m sure you can help out many users as I will also suggest this thread to people that come to me asking for datastore scripts.

19 Likes

Thank you for the response!
As for now I’m trying to use simple code to help new people and introducing them to this type of stuff, but i will look into UpdateAsync() as soon as i have time,

Thanks!

14 Likes

Overall, it looks very clean. There are a few suggestions I have.

  1. Have more comments that explain the code
  2. For the saving, where it says this:

change it to:

while wait(120) do
    saveData(player)
end


That way, the script can do other things while waiting for the 2 minutes to be up.

Edit: This just changes the way the code looks, reducing a line of text, and also makes it a little bit more visually appealing

Other than that, nice work!

10 Likes

Thanks, i will definitely change that. And I will add more comments aswell.

5 Likes

That is a big no.
wait() is not a conditional statement as it can be used for while loops but is not suggested.
Nor does while wait allow you to run multiple tasks at the same time.

Read that document above then you will understand why.

Edit:

You should rely on these posts rather than mine.

New POV

Looking back at what I said, it does have a lot of nonsense.

At the time, the article mentioned something in the lines of “while wait allows you to run multiple tasks at the same time” which is the reason I felt obliged of responding to that statement.

Although it does have better readability, some just prefer while true do for the reason of habit. It makes some’s workflow quicker by being familiar while reading through the code. But this is a really minor point. It’s not like a simple “wait(x)” will make you waste more than a second understand what’s happening.

I wouldn’t consider it a tool though, I’d say it’s more of a preference. You either go for while true do wait() or while wait() do and I’m pretty certain you would pick one and stick to it. I don’t really see a reason to be jumping from one to another other than the reason of readability which shouldn’t be an issue over a simple “wait(x)” affecting 1 or 2 lines.

15 Likes

That isn’t true. Putting wait(120) in the conditional won’t start a new thread.

15 Likes

Great tutorial! I have learned a lot from it. Hopefully now I can have reliable datastores.

On a separate note, how would I assign a name and a key so that it can be modified with say DataStore Editor V2?

4 Likes

Oh that’s also my bad for not mentioning, in the entire script at the beginning of the topic, theres

local dataStore = DataStoreService:GetDataStore("YourDataStoreName") -- You can change the name to anything you want to

And then when you open Datastore editor

Enter you game id, and datastore name and then connect…
After that it will ask for your Key, and as i said our key in the tutorial is the players userid, so just type in the userid you want to check

And then press querry

Then you can change, modify whatever you want to!

4 Likes

Tysm! Will you update the tutorial at all to be UpdateAsync() or is that something I will have to figure out on my own?

1 Like

No need to use UpdateAsync() for now, i know some really really rare scenarios u will need the UpdateAsync() but you can stick with SetAsync() as it works perfectly fine, But yeah i will update the topic, In fact im updating it right now, in like 10 - 20 mins it will be updated!

Have a good day!

1 Like

Thank you so much! I will definitely come to you if I have any questions! :heart_decoration:

1 Like

In that document, one of the points it made was that using while wait() is normally used and makes the code messier and less readable:

Screen Shot 2020-08-20 at 10.00.15 PM

There, in that instance, I would agree, don’t use while wait. But in this case, I don’t see how the readability is any worse.

Also, another one of the points was that you didn’t get a return value of wait(). In this case, it wouldn’t matter.

Screen Shot 2020-08-20 at 10.04.35 PM Screen Shot 2020-08-20 at 10.04.51 PM

As it said, from a functionality standpoint, it’s not a problem in this situation. In the case of this datastore, there is no need for us to know how long it has actually been yielded for.

The only thing we need is for the autosave to run every two minutes, and we don’t need to know how long it actually took, we just need it to autosave about every 2 mins.

Edit: The way Roblox’s wait function currently works it would wait more about 119.999999-ish seconds, so it truly won’t affect it in any negative way.

4 Likes

This is a duplicate of a tutorial from the DevHub.

Not only that the but content isn’t in conjunction with the title as it’s is clickbait

Issues found so far:

  • Not using Pcalls for SaveAsync
  • Not retrying failed Pcalls
  • Not using Coroutines in BindToClose
  • Not using UpdateAsync
  • Not checking for available Budget before DataStore calls
  • Not adding any cool-downs to DataStore calls
  • Not using GetPlayers instead of GetChildren
  • The loop inside PlayerAdded will continue to run after the player leaves

I recommend that you do not follow this tutorial as it causes data problems

21 Likes

Oops, my bad, must’ve been a bit tired and havent seen that, my bad.

3 Likes

I’m sorry to have those issues, but using this works perfectly fine to me, if they wanna know how to use coroutines and updateAsync, that’s on them. I understand that I could’ve mentioned it. But after all this is a tutorial for begginers, I’ve removed the auto-saving as i just saw that i it makes issues, and i fixed the GetChildren, I must have been tired and didn’t see it. Anyways thanks for the reply, have a great day

4 Likes

Quick point: You should update your DataStore Editor plugin to get V3!

9 Likes

I already got this one for 150 robux and i like this datastore plugin, but sure i can change it, can you link it to me i can’t find it ;3

1 Like

It’s the same one! Go to Studio > Plugins tab, and click Manage Plugins. Then update from there.

1 Like

Oh, thanks! Have a great day. :smiley:

2 Likes