โ† All guides
2025-05-05ยท7 min read

How to Make a Roblox Shop System (Buy Items with Cash)

Build a working Roblox shop system from scratch. Players spend in-game cash to buy tools and items. Includes server-side validation to prevent exploits.

Overview

A shop system in Roblox has two parts: a GUI the player clicks, and a server script that handles the purchase securely. Never process purchases on the client โ€” exploiters can fire RemoteEvents with any values they want.

The Golden Rule: Validate on the Server

Everything that changes game state (cash, inventory, items) must be validated server-side. The client sends a request, the server checks it, the server acts on it. Never trust the client.

Setting Up the RemoteEvent

In ServerScriptService, create the RemoteEvent that the shop GUI will fire:

local ReplicatedStorage = game:GetService("ReplicatedStorage")

local buyEvent = Instance.new("RemoteEvent")
buyEvent.Name = "BuyItem"
buyEvent.Parent = ReplicatedStorage

Defining Your Items

local ITEMS = {
    Sword  = { price = 50  },
    Shield = { price = 100 },
    Bow    = { price = 75  },
}

Keep your item definitions on the server. Never put prices in the client-side GUI code โ€” an exploiter can read and modify client-side Lua.

Handling the Purchase (Server)

local ServerStorage = game:GetService("ServerStorage")

buyEvent.OnServerEvent:Connect(function(player, itemId)
    -- Validate item exists
    local item = ITEMS[itemId]
    if not item then return end

    -- Validate player has enough cash
    local cash = player.leaderstats and player.leaderstats:FindFirstChild("Cash")
    if not cash or cash.Value < item.price then return end

    -- Validate tool exists in ServerStorage
    local tool = ServerStorage:FindFirstChild(itemId)
    if not tool then return end

    -- Process purchase
    cash.Value -= item.price
    tool:Clone().Parent = player.Backpack
    print(player.Name .. " bought " .. itemId)
end)

Notice how every step validates before acting. If anything is wrong, we just return โ€” no error, no crash.

The Client GUI (LocalScript)

In a LocalScript inside your shop GUI:

local ReplicatedStorage = game:GetService("ReplicatedStorage")
local buyEvent = ReplicatedStorage:WaitForChild("BuyItem")

-- Wire up your buy buttons
local buyButton = script.Parent:WaitForChild("BuyButton")
buyButton.MouseButton1Click:Connect(function()
    buyEvent:FireServer("Sword")
end)

Use WaitForChild to get the RemoteEvent โ€” it might not exist yet when the LocalScript runs.

Putting Tools in ServerStorage

Your tools need to live in ServerStorage, not the workspace. Drag your Tool objects into ServerStorage in the Explorer. Name them exactly as they appear in your ITEMS table โ€” "Sword", "Shield", etc.

Preventing Duplicate Purchases

Add a check so players can't buy a tool they already have:

-- Inside the OnServerEvent handler, before cloning:
if player.Backpack:FindFirstChild(itemId) or
   (player.Character and player.Character:FindFirstChild(itemId)) then
    return  -- already owns it
end

Ready-Made Script

Don't want to build this from scratch? Grab our complete Shop System script โ€” fully working, exploit-safe, with comments explaining every line.

Ready-made scripts for your game

Browse our free library of copy-paste Luau scripts โ€” no setup needed.

Browse Script Library โ†’
More guides
How to Make a Roblox DataStore (Save Player Data)6 min read โ†’Roblox Scripting for Beginners: Complete 2025 Guide8 min read โ†’Roblox NPC Scripting Guide: Pathfinding, Dialogue & More7 min read โ†’