How to Make Leaderstats in Roblox (Leaderboard Guide)

Quick answer: Leaderstats in Roblox are made by creating a Folder named exactly "leaderstats" inside each Player when they join, then adding value objects like IntValue for each stat you want to track. Roblox detects that folder automatically and displays its values in the player list leaderboard — no UI code required.

To make leaderstats in Roblox, create a Folder named exactly "leaderstats" inside each player as they join, and put value objects such as an IntValue inside it for every stat you want to show. Roblox watches for that specific folder name and automatically renders its values in the player list at the top right of the screen — you write no leaderboard UI yourself.

The whole setup lives in one server Script (usually in ServerScriptService), takes about twenty lines, and scales from a simple Coins counter to a full stat system.

Why the name "leaderstats" matters

Roblox's default player list has a special hook built in: if it finds a child of a Player whose Name is exactly "leaderstats", it reads that folder's children and shows each one as a column, using the object's Name as the column header and its Value as the cell.

Three consequences follow from that design:

Creating leaderstats when a player joins

Hook into Players.PlayerAdded and build the structure per player:

local Players = game:GetService("Players")

local function onPlayerAdded(player)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    local coins = Instance.new("IntValue")
    coins.Name = "Coins"
    coins.Value = 0
    coins.Parent = leaderstats
end

Players.PlayerAdded:Connect(onPlayerAdded)

Each value object becomes one column. IntValue holds whole numbers and covers most stats; use NumberValue for decimals, or StringValue/ObjectValue when a stat isn't numeric (for example, showing the player's current stage or equipped pet). The object's Name property is what players see, so "Coins" produces a "Coins" column.

If you also want to handle players who joined before your script ran (relevant in Studio play-solo timing), loop over Players:GetPlayers() once at startup and call onPlayerAdded for anyone already present.

A complete working example: coin pickups

Here is a full, runnable example. One script creates the leaderstats, and every part named "Coin" in workspace.Coins increments the collector's total when touched:

local Players = game:GetService("Players")

-- Set up leaderstats for every joining player
Players.PlayerAdded:Connect(function(player)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    local coins = Instance.new("IntValue")
    coins.Name = "Coins"
    coins.Value = 0
    coins.Parent = leaderstats
end)

-- Coin pickups
for _, coin in workspace.Coins:GetChildren() do
    local debounce = false

    coin.Touched:Connect(function(hit)
        if debounce then return end

        local character = hit.Parent
        local player = Players:GetPlayerFromCharacter(character)
        if not player then return end

        local leaderstats = player:FindFirstChild("leaderstats")
        local coinsStat = leaderstats and leaderstats:FindFirstChild("Coins")
        if not coinsStat then return end

        debounce = true
        coinsStat.Value += 1
        coin.Transparency = 1
        coin.CanTouch = false
        task.wait(5)               -- respawn delay
        coin.Transparency = 0
        coin.CanTouch = true
        debounce = false
    end)
end

Two details in this snippet matter beyond leaderstats. First, GetPlayerFromCharacter translates whatever touched the coin back into a player — otherwise a stray NPC limb or falling part would farm coins. Second, the debounce flag stops a single touch event from firing dozens of times as limbs brush past the part; the Touched event guide explains that pattern in depth, since nearly every touch-based mechanic needs it.

Updating stats anywhere else in your code

Because the value objects live under the player, any server script can reach them with a plain path lookup:

local function addCoins(player, amount)
    local coins = player:FindFirstChild("leaderstats")
        and player.leaderstats:FindFirstChild("Coins")
    if coins then
        coins.Value += amount
    end
end

Prefer FindFirstChild over direct indexing during joins: there is a brief window after PlayerAdded fires where another script may not have finished building the folder yet, and indexing a missing instance throws "attempt to index nil".

Saving leaderstats with DataStores

The default leaderboard resets on every server restart, so real games persist their values with DataStoreService. The usual shape is: load saved stats inside a pcall when the player joins, write them back when they leave, and call game:BindToClose() so shutdowns don't drop the final save:

local DataStoreService = game:GetService("DataStoreService")
local coinStore = DataStoreService:GetDataStore("PlayerCoins")

Players.PlayerAdded:Connect(function(player)
    local ok, saved = pcall(function()
        return coinStore:GetAsync("uid_" .. player.UserId)
    end)

    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player

    local coins = Instance.new("IntValue")
    coins.Name = "Coins"
    coins.Value = (ok and saved) or 0
    coins.Parent = leaderstats
end)

Players.PlayerRemoving:Connect(function(player)
    local coins = player:FindFirstChild("leaderstats")
        and player.leaderstats:FindFirstChild("Coins")
    if not coins then return end

    pcall(function()
        coinStore:SetAsync("uid_" .. player.UserId, coins.Value)
    end)
end)

For production, prefer UpdateAsync over SetAsync (it reads-then-writes atomically), and wrap every call in pcall because DataStore requests fail routinely under throttling. The full walkthrough of keys, budgets, and BindToClose is in the Roblox DataStore guide.

Common leaderstats mistakes

These account for almost every "my leaderboard doesn't work" question:

Do you ever need custom leaderboard UI?

Only when you outgrow the player list — global top-100 boards, team tables, or rich stat panels all require your own ScreenGui backed by ordered DataStores (GetOrderedDataStore). But the built-in leaderstats convention remains the correct foundation: it costs nothing, replicates reliably, and every experienced Roblox player looks at it instinctively.

Learn Luau by doing

Reading about leaderstats only gets you so far — the fastest way to internalize the PlayerAdded flow and event-driven updates is to build them yourself. Luablox walks you through these exact patterns step by step in its interactive lessons, with a reference library at /theory and hands-on challenges at /problems. Start with scripting for beginners if you want the full path from zero to your first working game systems.

Frequently asked questions

Why is my leaderstats folder not showing up in Roblox?

Check three things: the folder must be named exactly "leaderstats" (case-sensitive), it must be parented directly to the Player object, and it must be created by a server-side Script — folders made by a LocalScript never replicate and will not appear in the player list.

Can I make leaderstats with a LocalScript?

No. Instances created on the client exist only for that client, so a LocalScript-built leaderboard would be invisible to other players and would desync constantly. Create the leaderstats folder and value objects on the server, where changes replicate automatically.

What value objects can I use for leaderstats?

Any ValueBase descendant works: IntValue for whole numbers, NumberValue for decimals, StringValue for text like ranks, ObjectValue or BoolValue for non-numeric states. Each child of the leaderstats folder becomes one column, named after the object's Name property.

How do I keep leaderstats saved after the player leaves?

Use DataStoreService: load saved numbers inside a pcall during PlayerAdded and assign them to the IntValues, then save the current values in PlayerRemoving and game:BindToClose(). Use UpdateAsync for writes in production to avoid lost-update races.

Can I hide leaderstats from some players?

Not selectively through the built-in system — the player list shows the leaderstats folder to everyone. For per-player visibility you need custom UI: keep authoritative stats in server storage and render them with your own ScreenGui.

Learn core Roblox scripting and Luau programming concepts, including: how to make leaderstats roblox, leaderstats roblox, roblox leaderboard script, roblox player stats, roblox intvalue leaderstats.

Related pages