In short
Select an instance, scroll the Properties window to Attributes, click +, give it a name and a type and set the value. In Luau, instance:GetAttribute("Damage") reads it (nil when it is not set), instance:SetAttribute("Damage", 25) writes it, and instance:GetAttributeChangedSignal("Damage"):Connect(fn) runs fn when it changes. Attributes set on the server replicate to every player; attributes a LocalScript sets stay on that player's device.
- Attributes hold single values: text, numbers, booleans and Roblox types like Vector3, Color3 and CFrame. Not tables, not instances.
- Always handle
nilfromGetAttribute, with a default. - Set anything that matters (coins, levels, ownership) on the server only.
On this page
What attributes are
Every instance already has built-in properties such as Size and Color. Attributes sit next to them, under their own heading in the Properties window, and are saved with the place. They are the easiest way to give a script a setting without editing its code, and to share a small piece of state between scripts.
| Type | Example value | Typical use |
|---|---|---|
| string | "RedKey" | Names, modes, keys |
| number | 25 | Damage, speed, cooldowns, levels |
| boolean | true | Open, locked, enabled |
| Vector3, Vector2, CFrame | Vector3.new(0, 10, 0) | Offsets and positions |
| Color3, BrickColor | Color3.fromRGB(255, 0, 0) | Team or rarity colours |
| UDim, UDim2, NumberRange, NumberSequence, ColorSequence, Rect | varies | UI and effect settings |
Names may use letters and digits, plus periods, hyphens, slashes and underscores, up to 100 characters, and must not start with RBX, which Roblox keeps for itself. Spaces and symbols such as @ or ! are not allowed. Max Speed with a space is not allowed; use MaxSpeed.
Step 1: Read and write attributes
Insert a Part, add a number attribute Damage set to 20 in the Properties window, then put this Script inside it. It reads the setting, uses a default when the attribute is missing or the wrong type, and writes a second attribute from code.
-- Script inside a Part with a number attribute "Damage".
local part = script.Parent :: BasePart
-- A number attribute, with a default when it is missing or not a number
local function numberAttribute(instance: Instance, name: string, default: number): number
local value = instance:GetAttribute(name)
return if typeof(value) == "number" then value else default
end
local damage = numberAttribute(part, "Damage", 10)
print("This part deals", damage, "damage")
-- Set an attribute from code (it appears in the Properties window during Play)
part:SetAttribute("TimesTouched", 0)
part.Touched:Connect(function(hit: BasePart)
local humanoid = hit.Parent and hit.Parent:FindFirstChildOfClass("Humanoid")
if humanoid then
humanoid:TakeDamage(damage)
part:SetAttribute("TimesTouched", numberAttribute(part, "TimesTouched", 0) + 1)
end
end)
-- All attributes at once, as a table
for name, value in part:GetAttributes() do
print(name, "=", value)
end
Setting an attribute to nil removes it. Reading one that was never set gives nil, which is why the helper checks the type: a typo in the Properties window then falls back to the default instead of breaking the script with attempt to perform arithmetic on nil.
Step 2: React when an attribute changes
GetAttributeChangedSignal(name) fires when that one attribute changes; AttributeChanged fires for any attribute and passes its name. This is how a LocalScript can update a label whenever the server changes a player's level, with no RemoteEvent at all.
-- Script in ServerScriptService named Levels.
-- Keeps a Level attribute on each player; the client shows it.
local Players = game:GetService("Players")
Players.PlayerAdded:Connect(function(player: Player)
player:SetAttribute("Level", 1)
-- for this example: level up every 30 seconds
while player.Parent do
task.wait(30)
local level = player:GetAttribute("Level")
if typeof(level) == "number" then
player:SetAttribute("Level", level + 1)
end
end
end)
-- LocalScript in StarterPlayerScripts named LevelWatcher.
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local function show()
print("You are level", player:GetAttribute("Level"))
end
player:GetAttributeChangedSignal("Level"):Connect(show)
show() -- also show the value it already has
Call the function once yourself after connecting, as show() does: the signal only fires on changes, so a value set before your script started would otherwise never be shown.
Step 3: What replicates, and what to trust
| Set by | On an instance that | Who sees the change |
|---|---|---|
| A server Script | replicates (Workspace, ReplicatedStorage, the Player) | The server and every player |
| A server Script | is in ServerStorage or ServerScriptService | The server only |
| A LocalScript | anything | Only that player; the server never sees it |
This makes attributes a safe way to show server state on clients, and an unsafe way to receive anything from them. A cheater can set any attribute they like on their own device, but the server keeps its own value, so as long as the server reads its own attributes, a client-side change does nothing. When the client needs to ask for a change, use a RemoteEvent and let the server decide, as the RemoteEvents guide explains.
Attributes or Value objects?
Before attributes existed, the same job was done with child objects such as IntValue, StringValue and BoolValue. Both still work.
| Use | When |
|---|---|
| An attribute | Settings and state on an object: damage, speed, open, level. Fewer instances, nothing to WaitForChild. |
| An IntValue or NumberValue | The leaderboard: Roblox only shows values inside a leaderstats folder, so stats there must be Value objects. |
| A NumberValue | Something you want to tween smoothly, as the TweenService guide does for models. |
| An ObjectValue | Pointing at another instance. Attributes cannot hold instances. |
| A ModuleScript table | Lists and tables of data. Attributes cannot hold tables. |
Common errors and fixes
Open the Output window (Window menu, then Output) before you press Play.
GetAttribute returns nil
The name does not match exactly (capitals count), the attribute is on a different instance, or it was set by a LocalScript and you are reading it on the server. Look at the instance's Attributes section during Play, switching between the client and server views.
SetAttribute says the name is invalid
Names may only use letters, digits, periods, hyphens, slashes and underscores, up to 100 characters, and cannot start with RBX. Remove spaces and other symbols.
Attribute is not a supported type
You passed a table or an instance. Store a table in a ModuleScript or as JSON text, and an instance in an ObjectValue.
The client does not see the server's change
The instance is somewhere that does not replicate, such as ServerStorage, or the LocalScript only read the value once. Use GetAttributeChangedSignal.
Build it with RoCode
If you would rather not set this up by hand, RoCode can build it in the place you have open. RoCode is an independent AI agent for Roblox Studio, not made by Roblox: you describe the change in a web chat, and its Studio plugin creates the scripts and instances in your Explorer, so there is no code to paste.
Move the hard-coded damage and cooldown numbers in my sword scripts into Damage and Cooldown attributes on each sword Tool, read on the server with defaults of 20 and 0.5.
- Can find the numbers you mean with Search Scripts and read the scripts first
- Can set attributes on your instances and edit the scripts to read them, then compile-check each one with Check Script
- Sets an undo point before and after each batch of changes, so Ctrl+Z steps back one batch at a time
With plugin 3.9 or newer RoCode can run a short playtest and read the errors, but it checks only what it chose to test, so try the changed objects yourself. How RoCode connects to Studio.
Questions
What are attributes in Roblox?
Custom named values you add to any instance, next to its built-in properties. Scripts read them with GetAttribute, change them with SetAttribute and listen with GetAttributeChangedSignal.
Do attributes replicate to the client?
Yes, when the server sets them on an instance that replicates. Changes a client makes stay on that client.
Can an attribute store a table?
No. Use several attributes, a ModuleScript, or encode the table as text with HttpService:JSONEncode if it really must sit on the instance.
Are attributes faster than IntValues?
They avoid creating extra instances and waiting for children, which helps when you have thousands of objects. For a handful the difference is small; choose by what reads more clearly.
Are attributes saved between game sessions?
Attributes you set in Studio are saved with the place. Values set while the game runs are lost when the server closes; save player data with a data store.
Sources and further reading
- Roblox Creator Docs: Attributes. types, naming rules and replication
- Roblox Creator Docs: Instance:SetAttribute
- Roblox Creator Docs: Instance:GetAttributeChangedSignal
- Roblox Creator Docs: Properties window. adding attributes in Studio
How the code was checked: every script on this page passes Luau's strict type checker against Roblox's API definitions (luau-lsp, 5 November 2026). A type check catches misspelt APIs and wrong types, not game logic, so playtest in Studio before you publish.