9 min read

Source: Roblox Creator Hub · CC BY 4.0 · View source · Code samples: MIT Imported 2026-10-03. Formatting adapted for this site.

Data stores

The DataStoreService lets you store data that needs to persist between sessions, like items in a player's inventory or skill points. Data stores are consistent per game, so any place in a game can access and change the same data, including places on different servers.

If you want to add granular permission control to your data stores and access them outside of Studio or Roblox servers, you can use Open Cloud APIs for data stores.

To view and monitor all the data stores in a game through the Creator Hub, use the Data Stores Manager.

For temporary data that you need to update or access frequently, use memory stores.

Enable Studio access

By default, games tested in Studio can't access data stores, so you must first enable them. Accessing data stores in Studio can be dangerous for live games because Studio accesses the same data stores as the client application. To avoid overwriting production data, do not enable this setting for live games. Instead, enable it for a separate test version of the game.

To enable Studio access in a published game:

  1. Open Studio's File ⟩ Experience Settings window.
  2. Navigate to Security.
  3. Enable the Enable Studio Access to API Services toggle.
  4. Click Save.

Access data stores

To access a data store inside a game:

  1. Add DataStoreService to a server-side Script.
  2. Use the GetDataStore() function and specify the name of the data store you want to use. If the data store doesn't exist, Studio creates one when you save your game data for the first time.
local DataStoreService = game:GetService("DataStoreService")

local gameStore = DataStoreService:GetDataStore("PlayerGame")

Note

The server can only access data stores through Scripts. Attempting client-side access in a LocalScript causes an error.

Create data

A data store is essentially a dictionary, similar to a Luau table. A unique key indexes each value in the data store, like a user's unique Player.UserId or a named string for a game promo.

**User data key** **Value**
`31250608` 50
`351675979` 20
`505306092` 78000
**Promo data key** **Value**
`ActiveSpecialEvent` SummerParty2
`ActivePromoCode` BONUS123
`CanAccessPartyPlace` true

To create a new entry, call SetAsync() with the key name and a value.

local DataStoreService = game:GetService("DataStoreService")

local gameStore = DataStoreService:GetDataStore("PlayerGame")

local success, errorMessage = pcall(function()
	gameStore:SetAsync("User_1234", 50)
end)
if not success then
	print(errorMessage)
end

Note

Functions like SetAsync() that access a data store's contents are network calls that might occasionally fail. To catch and handle errors, make sure to wrap these calls in LuaGlobals.pcall().

Update data

To change any stored value in a data store, call UpdateAsync() with the entry's key name and a callback function that defines how you want to update the entry. This callback takes the current value and returns a new value based on the logic you define. If the callback returns nil, the write operation is cancelled and the value isn't updated.

Note

The callback function you pass into UpdateAsync() does not have permission to yield. It can't contain any yielding functions like task.wait().

local DataStoreService = game:GetService("DataStoreService")

local nicknameStore = DataStoreService:GetDataStore("Nicknames")

local function makeNameUpper(currentName)
	local nameUpper = string.upper(currentName)
	return nameUpper
end

local success, updatedName = pcall(function()
	return nicknameStore:UpdateAsync("User_1234", makeNameUpper)
end)
if success then
	print("Uppercase Name:", updatedName)
end

Set vs update

Use set to quickly update a specific key. The SetAsync() function:

Use update to handle multi-server attempts. The UpdateAsync() function:

Read data

To read the value of a data store entry, call GetAsync() with the entry's key name.

local DataStoreService = game:GetService("DataStoreService")

local gameStore = DataStoreService:GetDataStore("PlayerGame")

local success, currentGame = pcall(function()
	return gameStore:GetAsync("User_1234")
end)
if success then
	print(currentGame)
end

Note

The values you retrieve using GetAsync() sometimes can be out of sync with the backend due to the caching behavior. For more information, see Disabling caching.

Increment data

To increment an integer in a data store, call IncrementAsync() with the entry's key name and a number for how much to change the value. IncrementAsync() is a convenience function that lets you avoid calling UpdateAsync() and manually incrementing the integer.

local DataStoreService = game:GetService("DataStoreService")

local gameStore = DataStoreService:GetDataStore("PlayerGame")

local success, newGame = pcall(function()
	return gameStore:IncrementAsync("Player_1234", 1)
end)
if success then
	print(newGame)
end

Remove data

To remove an entry and return the value associated with the key, call RemoveAsync().

local DataStoreService = game:GetService("DataStoreService")

local nicknameStore = DataStoreService:GetDataStore("Nicknames")

local success, removedValue = pcall(function()
	return nicknameStore:RemoveAsync("User_1234")
end)
if success then
	print(removedValue)
end

Metadata

Note

Ordered data stores don't support versioning and metadata, so DataStoreKeyInfo is always nil for keys in an OrderedDataStore. If you need to support versioning and metadata, use DataStore.

There are two types of metadata associated with keys:

To manage metadata, expand the SetAsync(), UpdateAsync(), GetAsync(), IncrementAsync(), and RemoveAsync() functions.

Note

When calling SetAsync(), IncrementAsync(), and UpdateAsync(), you must always update metadata definitions with a value, even when there are no changes to the current value. If you don't, you lose the current value.

For limits when defining metadata, see the metadata limits.

Ordered data stores

By default, data stores don't sort their content. If you need to get data in an ordered way, like in persistent leaderboard stats, call GetOrderedDataStore() instead of GetDataStore().

local DataStoreService = game:GetService("DataStoreService")

local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")

Ordered data stores support the same basic functions as default data stores, plus the unique GetSortedAsync() function. This retrieves multiple sorted keys based on a specific sorting order, page size, and minimum/maximum values.

The following example sorts character data into pages with three entries, each in descending order, then loops through the pages and outputs each character's name and age.

local DataStoreService = game:GetService("DataStoreService")

local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")

-- Populates ordered data store
local characters = {
	Mars = 19,
	Janus = 20,
	Diana = 18,
	Venus = 25,
	Neptune = 62
}
for char, age in characters do
	local success, errorMessage = pcall(function()
		characterAgeStore:SetAsync(char, age)
	end)
	if not success then
		print(errorMessage)
	end
end

-- Sorts data by descending order into pages of three entries each
local success, pages = pcall(function()
	return characterAgeStore:GetSortedAsync(false, 3)
end)
if success then
	while true do
		-- Gets the current (first) page
		local entries = pages:GetCurrentPage()
		-- Iterates through all key-value pairs on page
		for _, entry in entries do
			print(entry.key .. " : " .. tostring(entry.value))
		end
		-- Checks if last page has been reached
		if pages.IsFinished then
			break
		else
			print("----------")
			-- Advances to next page
			pages:AdvanceToNextPageAsync()
		end
	end
end

Note

When you iterate through GetOrderedDataStore() using AdvanceToNextPageAsync(), the limit for requests is the same as the maximum page size you set for an ordered data store. AdvanceToNextPageAsync() always has the same limit as the class that originally requires it.

Read multiple entries

To read multiple ordered data store entries in a single request, call BatchGetAsync() with an array of keys. This is the batch counterpart to reading entries one at a time with GetAsync().

BatchGetAsync() returns a dictionary that maps each requested key to a table with a value field. Keys that don't exist are omitted from the dictionary, so confirm that a key is present before reading its value.

Each key you request counts as one read request, so a single call for N keys counts as N requests against the ordered data store read limit.

The following example reads three player scores in a single request, then loops through the keys and outputs each score that exists.

local DataStoreService = game:GetService("DataStoreService")

local playerScores = DataStoreService:GetOrderedDataStore("PlayerScores")
local keys = {"Player_123", "Player_456", "Player_789"}

local success, results = pcall(function()
	return playerScores:BatchGetAsync(keys)
end)
if success then
	for _, key in keys do
		local entry = results[key]
		if entry then
			print(key .. " : " .. tostring(entry.value))
		else
			print(key .. " has no saved entry")
		end
	end
end