MCPInstall

roblox-datastores

Use when implementing player data persistence in Roblox, saving/loading player stats or inventory, building leaderboards with ordered datastores, handling data migration between versions, diagnosing data loss issues, or adding auto-save and shutdown-safe data handling with DataStoreService.

Installs
604
Last 24h
—
Trending rank
—
Security
Not audited

Install

Works with every agent the skills CLI supports.

npx skills add https://github.com/sentinelcore/roblox-skills --skill roblox-datastores
  1. 01

    Install

    Run the command in your project. The CLI asks which agents to install for.

  2. 02

    Describe the task

    Ask your agent for something this skill covers. It loads roblox-datastores automatically when relevant.

  3. 03

    Review the result

    The agent follows the SKILL.md steps, scripts and references bundled with the skill.

SKILL.md

The instructions your agent reads when the skill is triggered.

roblox-datastores

Reference for Roblox DataStoreService — saving, loading, and managing player data on the server.

Quick Reference

MethodSignatureNotes
GetDataStoreDSS:GetDataStore(name, scope?)Returns a GlobalDataStore
GetOrderedDataStoreDSS:GetOrderedDataStore(name, scope?)For leaderboards
GetAsyncstore:GetAsync(key)Returns value or nil
SetAsyncstore:SetAsync(key, value)No return value needed
UpdateAsyncstore:UpdateAsync(key, fn)Atomic read-modify-write
RemoveAsyncstore:RemoveAsync(key)Deletes key, returns old value
GetSortedAsyncorderedStore:GetSortedAsync(asc, pageSize)Returns DataStorePages

Basic Setup

-- Server Script (ServerScriptService)
local DataStoreService = game:GetService("DataStoreService")
local Players = game:GetService("Players")

local playerStore = DataStoreService:GetDataStore("PlayerData_v1")

local DEFAULT_DATA = {
    coins = 0,
    level = 1,
    xp = 0,
}

Loading Data (GetAsync + pcall)

Always wrap datastore calls in pcall. They can fail due to network issues or rate limits.

local function loadData(player)
    local key = "player_" .. player.UserId
    local success, data = pcall(function()
        return playerStore:GetAsync(key)
    end)

    if success then
        local result = {}
        for k, v in pairs(DEFAULT_DATA) do result[k] = v end
        if data then
            for k, v in pairs(data) do result[k] = v end
        end
        return result
    else
        warn("Failed to load data for", player.Name, ":", data)
        return nil -- signal failure; do not give default data silently
    end
end

Saving Data (SetAsync vs UpdateAsync)

Use SetAsync for simple overwrites. Use UpdateAsync when the value must be based on the current stored value (e.g., incrementing a counter safely across servers).

-- Simple save
local function saveData(player, data)
    local key = "player_" .. player.UserId
    local success, err = pcall(function()
        playerStore:SetAsync(key, data)
    end)
    if not success then
        warn("Failed to save data for", player.Name, ":", err)
    end
end

-- Atomic increment with UpdateAsync
local function addCoinsAtomic(userId, amount)
    local key = "player_" .. userId
    pcall(function()
        playerStore:UpdateAsync(key, function(current)
            current = current or { coins = 0 }
            current.coins = current.coins + amount
            return current
        end)
    end)
end

Retry Logic

local MAX_RETRIES = 3
local RETRY_DELAY = 2

local function safeGet(store, key)
    for attempt = 1, MAX_RETRIES do
        local success, result = pcall(function()
            return store:GetAsync(key)
        end)
        if success then return true, result end
        warn(string.format("GetAsync attempt %d/%d failed: %s", attempt, MAX_RETRIES, result))
        if attempt < MAX_RETRIES then task.wait(RETRY_DELAY) end
    end
    return false, nil
end

Auto-Save: PlayerRemoving + BindToClose

Server shutdown without BindToClose silently discards unsaved data.

local sessionData = {} -- [userId] = data table

Players.PlayerAdded:Connect(function(player)
    local data = loadData(player)
    if data then
        sessionData[player.UserId] = data
    else
        player:Kick("Could not load your data. Please rejoin.")
    end
end)

Players.PlayerRemoving:Connect(function(player)
    local data = sessionData[player.UserId]
    if data then
        saveData(player, data)
        sessionData[player.UserId] = nil
    end
end)

-- Flush all sessions on server shutdown
game:BindToClose(function()
    for userId, data in pairs(sessionData) do
        local key = "player_" .. userId
        pcall(function()
            playerStore:SetAsync(key, data)
        end)
    end
end)

Ordered DataStores (Leaderboards)

Values must be positive integers.

local coinsLeaderboard = DataStoreService:GetOrderedDataStore("Coins_v1")

local function setLeaderboardScore(userId, coins)
    pcall(function()
        coinsLeaderboard:SetAsync("player_" .. userId, math.floor(coins))
    end)
end

local function getTopPlayers(count)
    local success, pages = pcall(function()
        return coinsLeaderboard:GetSortedAsync(false, count) -- false = descending
    end)
    if not success then return {} end

    local results = {}
    for rank, entry in ipairs(pages:GetCurrentPage()) do
        table.insert(results, { rank = rank, userId = entry.key, score = entry.value })
    end
    return results
end

Data Versioning / Migration

Include a _version field and migrate in the load path.

local CURRENT_VERSION = 2

local function migrateData(data)
    local version = data._version or 1
    if version < 2 then
        data.coins = data.gold or 0  -- renamed field
        data.gold = nil
        data._version = 2
    end
    return data
end

Use a versioned datastore name (PlayerData_v2) for breaking schema changes.


Common Mistakes

MistakeConsequenceFix
No pcall around datastore callsUnhandled error crashes the scriptAlways wrap in pcall
Saving on every Changed eventHits rate limits (60 + numPlayers×10 writes/min)Throttle; save on remove + periodic interval
No BindToClose handlerData lost on server shutdownAlways flush all sessions in BindToClose
Giving default data on load failurePlayer silently loses progressReturn nil on failure; kick or retry
SetAsync for atomic countersRace condition across serversUse UpdateAsync for read-modify-write
Storing Instances or functionsData silently dropsStore only strings, numbers, booleans, plain tables
Reusing datastore name after schema changeOld shape clashes with new codeAppend _v2, _v3 to name on breaking changes

FAQ

What does the roblox-datastores skill do?

Use when implementing player data persistence in Roblox, saving/loading player stats or inventory, building leaderboards with ordered datastores, handling data migration between versions, diagnosing data loss issues, or adding auto-save and shutdown-safe data handling with DataStoreService.

How do I install roblox-datastores?

Run npx skills add https://github.com/sentinelcore/roblox-skills --skill roblox-datastores in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/roblox-datastores/ (personal) or .claude/skills/roblox-datastores/ (project).

Which AI agents can use roblox-datastores?

Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.

Is roblox-datastores safe to install?

No partner security audit is available yet. Skills can run commands and scripts, so read the SKILL.md and any bundled files before installing.

Who maintains roblox-datastores?

It is published by sentinelcore in sentinelcore/roblox-skills. It has 604 recorded installs.

More from sentinelcore/roblox-skills

View all →

roblox-gui

sentinelcore/roblox-skills

Use when building, animating, or debugging Roblox GUI elements including HUDs, menus, world-space UI, and player labels. Triggers on: ScreenGui setup, SurfaceGui or BillboardGui placement, UDim2 sizing questions, TweenService UI animations, responsive scaling, LocalScript GUI logic, ResetOnSpawn issues, or any Frame/TextLabel/ImageButton layout work.

Frontend & Design1.2K installs

roblox-animations

sentinelcore/roblox-skills

Use when working with Roblox animation systems including playing, stopping, or blending animations on Humanoid characters or non-Humanoid models, handling AnimationTrack events, replacing default character animations, or debugging animation priority and blending issues.

Frontend & Design911 installs

roblox-performance

sentinelcore/roblox-skills

Use when optimizing a Roblox game for better frame rates, reducing lag, improving server or client performance, diagnosing FPS drops, handling large worlds, or when asked about streaming, draw calls, object pooling, LOD, MicroProfiler, or expensive loop operations.

roblox-security

sentinelcore/roblox-skills

Use when writing Roblox game scripts that handle player actions, currencies, stats, damage, or any RemoteEvent/RemoteFunction communication. Use when reviewing code for exploitable patterns, implementing anti-cheat logic, validating client requests on the server, or setting up rate limiting.

Security712 installs

roblox-remote-events

sentinelcore/roblox-skills

Use when implementing client-server communication in Roblox, firing events between LocalScripts and Scripts, passing data across the network boundary, syncing game state, or defending against exploits that abuse RemoteEvents or RemoteFunctions.

Backend & APIs579 installs

roblox-monetization

sentinelcore/roblox-skills

Use when developing Roblox games or experiences and need to earn Robux through Game Passes, Developer Products, UGC avatar items, or Premium Payouts — covers both Studio scripting and Creator Hub dashboard setup.

Media & Creative565 installs

Popular code quality & workflow skills

View category →

grill-me

mattpocock/skills

A relentless interview to sharpen a plan or design.

Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.

handoff

mattpocock/skills

Compact the current conversation into a handoff document for another agent to pick up.

domain-modeling

mattpocock/skills

Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording or editing an ADR.

codebase-design

mattpocock/skills

Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.

diagnosing-bugs

mattpocock/skills

Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.