Mastering GetDescendants() in Roblox Lua: A Complete Guide
- Primal Cam
- Aug 30
- 4 min read
When you start scripting in Roblox, one of the most powerful skills you can learn is how to navigate and control the hierarchy of objects in a game. Every game you build is made of Instances (parts, models, GUIs, sounds, scripts, etc.), and these Instances are arranged in a tree-like structure. Sometimes, you need to grab a specific object. Other times, you want everything inside of something — and that’s where GetDescendants() shines.
This article will guide you through what GetDescendants() is, how it works, when to use it, common mistakes, performance tips, and advanced tricks. By the end, you’ll know exactly how to wield it like a pro.
What Is GetDescendants()?
In Roblox, almost every object is an Instance. Each Instance can have children (objects directly inside of it). You may already know about GetChildren(), which returns the direct children of an Instance.
But what if you want every object inside, no matter how deeply nested? That’s where GetDescendants() comes in.
👉 Definition:Instance:GetDescendants() returns an array (table) containing all descendants of the Instance — that means children, children of children, children of children of children, and so on.
Example: The Difference Between GetChildren() and GetDescendants()
Let’s say you have this structure:

Model:GetChildren() → returns {Part, Folder}
Model:GetDescendants() → returns {Part, Folder, Part}
Notice how GetDescendants() digs deeper and grabs everything inside.
Basic Usage
Here’s a simple script that prints all descendants of Workspace:
for _, descendant in pairs(workspace:GetDescendants()) do
print(descendant.Name)
end
This will list the name of every single object in your Workspace, no matter how nested.
Filtering Descendants
Of course, you don’t always want all objects. You might just want all the Parts in a Model.
local model = workspace.MyModel
for _, descendant in pairs(model:GetDescendants()) do
if descendant:IsA("Part") then
print("Found part: " .. descendant.Name)
end
end
👉 Here we’re using .IsA() to filter out only objects of type Part. This is super common when you want to change properties like color, material, or collision.
Practical Example 1: Changing All Parts in a Model
Let’s say you’ve built a house in Studio and grouped it into a Model called House. You want to turn every part in the house red:
local house = workspace.House
for _, descendant in pairs(house:GetDescendants()) do
if descendant:IsA("BasePart") then
descendant.Color = Color3.fromRGB(255, 0, 0)
end
end
Now every wall, roof piece, and floor tile becomes red — even if they were hidden inside folders or nested models.
Practical Example 2: Adding ClickDetectors Everywhere
Suppose you want to make every part in a Model clickable. Instead of manually inserting a ClickDetector into each Part, you can script it:
local model = workspace.House
for _, descendant in pairs(model:GetDescendants()) do
if descendant:IsA("BasePart") then
local detector = Instance.new("ClickDetector")
detector.Parent = descendant
end
end
This is where GetDescendants() saves you hours of manual work.
When Should You Use GetDescendants()?
✅ Great Use Cases
Bulk editing properties across many objects
Adding or removing items (like ClickDetectors, TouchTransmitters, or SurfaceGuis)
Searching deeply nested structures for specific objects
Applying scripts to procedurally generated models
⚠️ When to Be Careful
Large Hierarchies: If you call GetDescendants() on something huge (like Workspace in a large game), it can return thousands of objects.
Performance: Don’t spam it in RunService.Heartbeat or loops that run constantly. Use it when you need a snapshot, not repeatedly.
Performance Tips
Don’t Overuse It – If you only need direct children, use GetChildren(). It’s faster.
Cache Results – If your hierarchy won’t change often, call GetDescendants() once and reuse the results instead of calling it repeatedly.
Filter Early – Check IsA() before running heavy logic to avoid unnecessary work.
Advanced Trick 1: Combining with CollectionService
Sometimes, instead of scanning through everything, you can “tag” objects using CollectionService in Studio. But if you’ve already got a model and you want to quickly find all tagged descendants:

This combines the power of tags with deep searching.
Advanced Trick 2: Recursive Behavior Without GetDescendants()
For learning purposes, here’s how you could manually write your own GetDescendants() using recursion:
local function getAllDescendants(object)
local descendants = {}
for _, child in pairs(object:GetChildren()) do
table.insert(descendants, child)
for _, grandChild in pairs(getAllDescendants(child)) do
table.insert(descendants, grandChild)
end
end
return descendants
end
-- Example:
local myModel = workspace.House
local allDescendants = getAllDescendants(myModel)
print(#allDescendants)
This helps you understand what’s happening under the hood — GetDescendants() is basically a built-in recursive function.
Common Mistakes to Avoid
Using It in Loops Every Frame
game:GetService("RunService").Heartbeat:Connect(function() for _, d in pairs(workspace:GetDescendants()) do -- laggy! end end)
❌ This will destroy performance in big games.
Not FilteringIf you don’t check IsA(), you might try changing .Color on an object that doesn’t have that property, causing errors.
Confusing It with GetChildren()Beginners often mix these up. Remember:
GetChildren() = direct children only
GetDescendants() = everything inside
Real-World Example: Lighting System
Let’s say you’re building a dungeon and want every torch (a Part with a PointLight inside) to turn off at once.
local dungeon = workspace.Dungeon
for _, descendant in pairs(dungeon:GetDescendants()) do
if descendant:IsA("PointLight") then
descendant.Enabled = false
end
end
With one loop, every torchlight in your dungeon is turned off — no matter how deep inside the models they are.
Wrapping It All Up | Roblox GetDescendants
GetDescendants() is one of those functions that feels small but unlocks huge possibilities in Roblox scripting. It lets you:
Traverse complex hierarchies
Apply bulk changes to objects
Save time compared to manually editing every part
Create scalable, reusable systems
But like all powerful tools, you have to use it wisely. Don’t overuse it in performance-heavy situations. When you need speed, stick to GetChildren() or tagging systems.
Think of GetDescendants() as your treasure map through Roblox’s Instance hierarchy. With it, you can uncover and control every hidden piece of your game world.

$50
Product Title
Product Details goes here with the simple product description and more information can be seen by clicking the see more button. Product Details goes here with the simple product description and more information can be seen by clicking the see more button

$50
Product Title
Product Details goes here with the simple product description and more information can be seen by clicking the see more button. Product Details goes here with the simple product description and more information can be seen by clicking the see more button.

$50
Product Title
Product Details goes here with the simple product description and more information can be seen by clicking the see more button. Product Details goes here with the simple product description and more information can be seen by clicking the see more button.
Comments