Reference Instances Directly with Attributes

Hey Creators,

We’re launching Instance attributes in Studio beta. You can now point an attribute at another Instance directly instead of relying on a separate ObjectValue. This works through a new engine type called InstanceHandle.

What’s new?

Attributes let you store your own data on an instance, a number, a string, a Vector3, and so on. Until now, attributes could only hold plain data. If you wanted a part to point at another part, you had to add an ObjectValue as a child to hold the reference. Now an attribute can point at another Instance directly:

local part = script.Parent

-- Point an attribute at another Instance
part:SetAttribute("Target", workspace.TargetPart)

-- Read it back
local handle = part:GetAttribute("Target")
local target = handle:Get()   -- the Instance, or nil if it isn't available right now

if target then
	print("Target is", target.Name)
end

You pass an Instance to SetAttribute and it’s stored for you. When you read it back with GetAttribute, you get an InstanceHandle (not the Instance itself – see below). Call Wait() or Get() on the handle to grab the actual Instance.

Why a Handle Instead of the Instance

The short answer is replication. Sometimes, the Instance you’re pointing at might not exist on a client yet. If GetAttribute returned the Instance directly, it would have to return nil when the target isn’t around. But nil is also what you get when the attribute doesn’t exist at all. Those are two different situations, and you’d have no way to tell them apart.

InstanceHandle keeps them separate:

  • The attribute doesn’t exist → GetAttribute returns nil.
  • The attribute exists, but the target isn’t here right now → GetAttribute returns a handle, and handle:Get() returns nil.

The handle is also streaming-aware. If the target streams out, Get() starts returning nil. To wait for it instead, use Wait():

local handle = part:GetAttribute("Target")
if handle then
	-- get if it's here now, otherwise wait for it to stream in
	local target = handle:Wait()
	print("Target is", target.Name)
end

Wait() yields until the Instance is available. You can pass a timeout in seconds, and it returns nil if that time passes first.

More Examples

Reacting to changes

GetAttributeChangedSignal fires when the attribute is set to a new target or deleted, so you can react to it:

part:GetAttributeChangedSignal("Target"):Connect(function()
	local handle = part:GetAttribute("Target")
	if handle then
		local target = handle:Get()
		if target then
			print("New target:", target.Name)
		end
	end
end)

Note that this signal fires when the attribute itself changes. It does not fire when the referenced Instance streams in or out, or is destroyed.

Sending references over remotes

InstanceHandle isn’t just for attributes. It’s a normal engine type, so you can send it through a RemoteEvent. This is useful when the server sends a reference to an Instance that hasn’t reached the client yet. You send the handle now, and the client waits for the Instance to arrive:

-- Server
remote:FireClient(player, InstanceHandle.new(workspace.Boss))

-- Client
remote.OnClientEvent:Connect(function(handle)
	local boss = handle:Wait()
	print("Boss:", boss.Name)
end)

API

InstanceHandle

  • InstanceHandle.new(instance: Instance): InstanceHandle : creates a handle pointing at the given Instance.
  • handle:Get(): Instance? : the Instance if it’s available locally, nil otherwise. Does not yield.
  • handle:Wait(timeout: number?): Instance? : yields until the Instance is available. With a timeout in seconds, returns nil if that time passes first.
  • tostring(handle) : the target’s name, or “nil”.
  • handle1 == handle2 : true if they point at the same target.

Attributes

  • Instance:SetAttribute(name, value) : now accepts an Instance or an InstanceHandle. An Instance is wrapped for you. Passing nil deletes the attribute.
  • Instance:GetAttribute(name) : returns an InstanceHandle if the attribute holds a reference, or nil if the attribute doesn’t exist.
  • Instance:GetAttributes() : reference attributes appear as InstanceHandle values.
  • Instance:GetAttributeChangedSignal(name) : fires when the attribute is set to a new target or deleted.

Studio

  • Instance is now a type you can pick in the attribute dropdown in the Explorer, using the standard reference picker.

Try it out

Thanks for building with us. Try Instance references in your attributes and let us know how they work for you.

456 Likes

This topic was automatically opened after 10 minutes.

Huge!, One of the most awaited and requested features is finally live, Thank you guys for the progress, this allows us to be more focused on handling physicals instances as states and data

66 Likes

Needed this 3 years ago, fire update! Great work

36 Likes

Hi everyone, I like this feature but making a new type for it is very interesting and I want to see what others think Thank you everyone

10 Likes

I used to pray for times like this

23 Likes

This is huge. I LOVE IT! Cant wait to update my code to use it

19 Likes

This is amazing!!

Question: What is the lifecycle management setup for these InstanceHandles? Do we need to destroy/disconnect them? How does that work w/ Attribute-based InstanceHandles?

10 Likes

Extremely happy to see this! Will we be getting enums added to the dropdown anytime soon? Setting them via command line or scripts only is a pain (outside of plugins such as this)

13 Likes

Here i was just wanting an Instance type for attributes, but they went and made it even BETTER for replication purposes. FIRE UPDATE!!!

13 Likes

I always wondered how this feature would be handled when it was finally added, and my first impression is that everything about this feels right. I really like the addition of InstanceHandle and that it has uses outside of attributes. This is a very exciting update.

11 Likes

They hold a weak reference to the instance itself (if it is present) and will be cleaned up automatically by the garbage collector when they are no longer referenced in your scripts.

24 Likes

i genuiney cannot contain my excitement, but i guess i have to or else the devforum will tell me that i need a structured sentence or whatever.

9 Likes

Finally!
Thank you Roblox for making such a good and highly requested update!
I can’t wait to use this!

7 Likes

31 Likes

This is a huge win! Will these work as expected in Server Authority mode/ BindToSimulation loops?

4 Likes

I am so unbelievably happy. I’ve been wanting this since day 1 of attributes coming out

5 Likes

14 Likes

Amazing update. Thank you so much!

1 Like

Are there any plans to provide some sort of API to get an Instance’s underlying ID?

local workspace_id = Instance.toId(workspace)
local workspace_reference = Instance.fromId(id)

Since most people nowadays use network modules that automatically serialize outgoing data, doing so would be more convenient than sending a table of InstanceHandles

27 Likes