StudioSort Pro | Folder Organization Plugin

Get the plugin here!
StudioSort Pro - Creator Store

Source Code
-- StudioSort Pro v3
-- Major update: Safe locked checking, reference scanner, hover descriptions

local Selection = game:GetService("Selection")
local ChangeHistoryService = game:GetService("ChangeHistoryService")

----------------------------------------------------
-- Services
----------------------------------------------------

local SERVICES = {
	Workspace = game:GetService("Workspace"),
	ReplicatedStorage = game:GetService("ReplicatedStorage"),
	ServerStorage = game:GetService("ServerStorage"),
	StarterGui = game:GetService("StarterGui"),
	StarterPlayer = game:GetService("StarterPlayer")
}

local selectedServiceName = "Workspace"

----------------------------------------------------
-- Toolbar
----------------------------------------------------

local toolbar = plugin:CreateToolbar("StudioSort Pro")
local toggleButton = toolbar:CreateButton(
	"StudioSort",
	"Open StudioSort Pro",
	"rbxassetid://4458901886"
)

toggleButton.ClickableWhenViewportHidden = true

----------------------------------------------------
-- Dock Widget
----------------------------------------------------

local widgetInfo = DockWidgetPluginGuiInfo.new(
	Enum.InitialDockState.Right,
	true,
	false,
	700,
	600,
	400,
	400
)

local widget = plugin:CreateDockWidgetPluginGui("StudioSortPro_Widget", widgetInfo)
widget.Title = "StudioSort Pro v3"

----------------------------------------------------
-- UI Layout (Split View)
----------------------------------------------------

local root = Instance.new("Frame")
root.Size = UDim2.new(1,0,1,0)
root.BackgroundColor3 = Color3.fromRGB(35,35,35)
root.Parent = widget

local mainPanel = Instance.new("Frame")
mainPanel.Size = UDim2.new(0.5,0,1,0)
mainPanel.BackgroundTransparency = 1
mainPanel.Parent = root

local infoPanel = Instance.new("Frame")
infoPanel.Position = UDim2.new(0.5,0,0,0)
infoPanel.Size = UDim2.new(0.5,0,1,0)
infoPanel.BackgroundColor3 = Color3.fromRGB(30,30,30)
infoPanel.Parent = root

local layout = Instance.new("UIListLayout")
layout.Padding = UDim.new(0,8)
layout.HorizontalAlignment = Enum.HorizontalAlignment.Center
layout.Parent = mainPanel

----------------------------------------------------
-- Description Box
----------------------------------------------------

local descriptionTitle = Instance.new("TextLabel")
descriptionTitle.Size = UDim2.new(1,0,0,30)
descriptionTitle.BackgroundTransparency = 1
descriptionTitle.TextColor3 = Color3.new(1,1,1)
descriptionTitle.TextScaled = true
descriptionTitle.Text = "Description"
descriptionTitle.Parent = infoPanel

local descriptionLabel = Instance.new("TextLabel")
descriptionLabel.Position = UDim2.new(0,10,0,40)
descriptionLabel.Size = UDim2.new(1,-20,0,120)
descriptionLabel.BackgroundTransparency = 1
descriptionLabel.TextWrapped = true
descriptionLabel.TextColor3 = Color3.new(1,1,1)
descriptionLabel.TextYAlignment = Enum.TextYAlignment.Top
descriptionLabel.Text = "Hover over a button to see what it does."
descriptionLabel.Parent = infoPanel

----------------------------------------------------
-- Reference Results Panel
----------------------------------------------------

local referenceTitle = Instance.new("TextLabel")
referenceTitle.Position = UDim2.new(0,0,0,170)
referenceTitle.Size = UDim2.new(1,0,0,30)
referenceTitle.BackgroundTransparency = 1
referenceTitle.TextColor3 = Color3.new(1,1,1)
referenceTitle.TextScaled = true
referenceTitle.Text = "Script References"
referenceTitle.Parent = infoPanel

local referenceBox = Instance.new("TextBox")
referenceBox.Position = UDim2.new(0,10,0,210)
referenceBox.Size = UDim2.new(1,-20,1,-220)
referenceBox.BackgroundColor3 = Color3.fromRGB(45,45,45)
referenceBox.TextColor3 = Color3.new(1,1,1)
referenceBox.TextWrapped = false
referenceBox.ClearTextOnFocus = false
referenceBox.MultiLine = true
referenceBox.TextXAlignment = Enum.TextXAlignment.Left
referenceBox.TextYAlignment = Enum.TextYAlignment.Top
referenceBox.Text = "No scans yet."
referenceBox.Parent = infoPanel

----------------------------------------------------
-- Utility
----------------------------------------------------

local function createButton(text, description)
	local button = Instance.new("TextButton")
	button.Size = UDim2.new(1,0,0,36)
	button.BackgroundColor3 = Color3.fromRGB(60,60,60)
	button.TextColor3 = Color3.new(1,1,1)
	button.TextScaled = true
	button.Font = Enum.Font.SourceSans
	button.Text = text
	button.Parent = mainPanel
	
	button.MouseEnter:Connect(function()
		descriptionLabel.Text = description
	end)
	
	button.MouseLeave:Connect(function()
		descriptionLabel.Text = "Hover over a button to see what it does."
	end)
	
	return button
end

local function isLocked(instance)
	local success, result = pcall(function()
		return instance.Locked
	end)
	return success and result
end

----------------------------------------------------
-- Collect Objects
----------------------------------------------------

local function collectObjects()
	local selected = Selection:Get()
	local objects = {}

	if #selected == 0 then
		local service = SERVICES[selectedServiceName]
		for _, obj in ipairs(service:GetChildren()) do
			table.insert(objects, obj)
		end
		return objects
	end

	return selected
end

----------------------------------------------------
-- Reference Scanner
----------------------------------------------------

local function scanReferences(movedObjects)
	local results = {}

	local scripts = {}
	for _, obj in ipairs(game:GetDescendants()) do
		if obj:IsA("Script") or obj:IsA("LocalScript") or obj:IsA("ModuleScript") then
			table.insert(scripts, obj)
		end
	end

	for _, moved in ipairs(movedObjects) do
		for _, scriptObj in ipairs(scripts) do
			if scriptObj.Source:find(moved.Name) then
				table.insert(results, moved.Name .. " referenced in: " .. scriptObj:GetFullName())
			end
		end
	end

	if #results == 0 then
		referenceBox.Text = "No references found."
	else
		referenceBox.Text = table.concat(results, "\n")
	end
end

----------------------------------------------------
-- Organize
----------------------------------------------------

local function organize(strategy)
	local objects = collectObjects()
	if #objects == 0 then return end

	ChangeHistoryService:SetWaypoint("Before StudioSort v3")

	local rootFolder = Instance.new("Folder")
	rootFolder.Name = "StudioSorted_" .. os.time()
	rootFolder.Parent = objects[1].Parent

	local folderMap = {}
	local movedList = {}

	for _, obj in ipairs(objects) do
		if isLocked(obj) then
			continue
		end

		local key
		if strategy == "Class" then
			key = obj.ClassName
		elseif strategy == "Prefix" then
			key = string.match(obj.Name, "^(.-)_") or "NoPrefix"
		elseif strategy == "Service" then
			key = obj.Parent.Name
		end

		if not folderMap[key] then
			local f = Instance.new("Folder")
			f.Name = key
			f.Parent = rootFolder
			folderMap[key] = f
		end

		obj.Parent = folderMap[key]
		table.insert(movedList, obj)
	end

	ChangeHistoryService:SetWaypoint("After StudioSort v3")

	scanReferences(movedList)
end

----------------------------------------------------
-- Buttons
----------------------------------------------------

createButton(
	"Organize by Class",
	"Groups objects into folders based on their ClassName."
).MouseButton1Click:Connect(function()
	organize("Class")
end)

createButton(
	"Organize by Name Prefix",
	"Groups objects based on the text before the first underscore."
).MouseButton1Click:Connect(function()
	organize("Prefix")
end)

createButton(
	"Organize by Service",
	"Groups objects based on their parent service."
).MouseButton1Click:Connect(function()
	organize("Service")
end)

toggleButton.Click:Connect(function()
	widget.Enabled = not widget.Enabled
end)

I hear by give full permission for modifying, using, sharing, tutorials, using as an example, and selling (only for free) of this Plugin, I do not consent to black market sales, or priced sales with the goal of making a profit. I would also appreciate credit if you are using the base unmodified plugin.

StudioSort Pro

Advanced Explorer Organization Plugin

Overview

StudioSort Pro is a lightweight productivity plugin for Roblox Studio that helps you clean up messy Explorer hierarchies in seconds.

If you’ve ever imported a free model and ended up with scripts, parts, meshes, and random folders all mixed together, this plugin is built to fix that. Instead of manually dragging everything into
folders, you select what you want and organize it instantly.

It supports multiple sorting modes, optional descendant handling, and full undo support.


Why I Made This

Explorer clutter slows development down. It makes debugging harder, finding assets frustrating, and collaboration messy.

StudioSort Pro doesn’t force a specific workflow. It works with however you already build and just speeds up the organization part.


Features

Multiple Sorting Modes

  • Organize by Class
  • Organize by Name Prefix
  • Organize by Service

Include Descendants Toggle
Choose whether child objects inside your selection should also be sorted.

Undo Support
Fully integrated with Roblox Studio’s undo system. One Ctrl + Z restores everything.

Dockable UI
Clean panel that behaves like any other Studio window.

Non Destructive Workflow
Each run creates a new organized folder so you don’t overwrite existing structures.

Available to scan all if non selected.
If you do not select anything it will automatically scan for sorting and will sort everything!


Installation (for direct use of source code)

  1. Open Roblox Studio
  2. Go to the Plugins tab
  3. Click Create New Plugin Script
  4. Paste in the StudioSort Pro code
  5. Save

After saving, you’ll see a new toolbar called StudioSort Pro. Click the StudioSort button to open the panel.


How to Use StudioSort Pro

Step 1: Select Objects

In the Explorer window, select the objects you want to organize.

You can:

  • Hold Ctrl to select multiple items
  • Hold Shift to select a range
  • Select models, parts, scripts, UI elements, or entire folders

Step 2: Choose a Sorting Method

Organize by Class

Groups objects based on their class type.

Example:

  • All Part instances go into a Part folder
  • All Script instances go into a Script folder
  • All Model instances go into a Model folder

Best used after importing assets or cleaning up Workspace.


Organize by Name Prefix

Groups objects based on the part of their name before an underscore.

Example:

Enemy_Zombie
Enemy_Soldier

Both go into a folder named Enemy

UI_Button
UI_Frame

Both go into a folder named UI

Objects without an underscore are placed into a folder called NoPrefix.

This mode works best if you follow consistent naming conventions.


Organize by Service

Groups objects based on their original parent location.

If you select items from Workspace and ReplicatedStorage, they’ll be separated accordingly inside the organized folder.

Useful when restructuring larger systems.


Include Descendants

The Include Descendants toggle changes how deep the sorting goes.

When OFF
Only the objects you directly selected are moved.

When ON
All children inside those objects are also included. This includes nested parts, scripts inside models, UI elements, etc.

If you’re selecting large models, double check this setting before running the plugin.


Undoing Changes

StudioSort Pro creates proper history waypoints.

If something doesn’t look right, press:

Ctrl + Z

Everything will revert instantly.


What Gets Created

Each time you run the plugin, it creates a folder named:

StudioSorted_timestamp

This folder appears in the same location as your selected objects.

Inside it, subfolders are generated based on the sorting method you chose.


Performance Notes

On very large selections with Include Descendants enabled, Studio may pause briefly while reorganizing instances. This is normal.

If you’re sorting thousands of objects, give it a moment to finish.


Best Use Cases

  • Cleaning imported free models
  • Reorganizing older projects
  • Separating scripts from parts quickly
  • Enforcing naming conventions
  • Preparing projects before team collaboration
  • Making large UI hierarchies easier to read

Known Limitations

  • The plugin only reorganizes selected objects.
  • It does not rename objects. It only groups them.

Planned Improvements

Depending on feedback, possible future additions include:

  • Saved user preferences
  • One-click sorting of entire services
  • Custom sorting rules
  • Color-coded folder generation
  • Preview window before execution

Update Log

v2.0 – Big Update

This update makes StudioSort Pro a lot more usable in real projects. The original version worked fine for quick sorting, but it needed more control and safety, especially for bigger games.

Here’s what’s new.

Dry Run Mode
You can now run the plugin without actually moving anything. It’ll show you how many objects would be processed, but your hierarchy stays the same. This is really helpful if you’re working with a big selection and don’t want to risk messing something up.

Settings Now Save
Your toggles (Include Descendants, Dry Run, Merge Mode, Clear Selection) now save between Studio sessions. You don’t have to reconfigure everything every time you reopen Studio.

Merge Into Existing Folder
Instead of creating a new timestamped folder every run, you can now merge everything into a single folder called StudioSorted. Makes repeated cleanup passes way cleaner.

Locked Instances Are Skipped
If something is locked, the plugin won’t try to move it. It just skips it and tells you how many were skipped. No weird errors or unexpected behavior.

Status Feedback
After running, the plugin now tells you how many objects were processed and how many were skipped. Small thing, but it makes it feel way more solid.

Clear Selection Option
There’s now a toggle to clear your selection after organizing. Handy if you’re cleaning a large scene in stages.

Under the Hood Changes

Undo handling is more reliable now.
Object collection logic is cleaner when Include Descendants is enabled.
Overall behavior is more stable with larger selections.

That’s it for v2.0. The goal here was to make it feel like something you can actually trust in a bigger project, not just a quick utility.

v2.1 Update

This update mainly improves how StudioSort Pro handles bigger cleanups.

If nothing is selected anymore, the plugin won’t just sit there. It will automatically scan a full service instead. You can pick which service it uses with the new service switch button. Right now it supports Workspace, ReplicatedStorage, ServerStorage, StarterGui, and StarterPlayer.

There’s also a new “Organize Entire Service” button if you want to force a full cleanup without selecting anything.

Overall this makes it way easier to clean up large projects without manually selecting everything first.

Other small improvements:

• Better folder handling when sorting entire services
• Cleaner root folder behavior
• More reliable locked instance skipping
• Improved feedback after large operations
• General performance tweaks

This update is mostly about making the plugin more practical for real projects instead of just small selections.

———————————

If you try it out and have suggestions, feel free to reply to the thread. I’m open to feedback and improvements!

Thanks for checking this post out : D

1 Like

When you check for obj.Locked in the organize function it stops the entire function if “Locked” isnt a child or property of the instance.

Also, I’m thinking it would be cool if the plugin also went thru scripts and refactored places where the object was mentioned for each object being iterated over or at least displayed the places where the object is mentioned (for ppl who aren’t familiar with “find all”). I think this would make the plugin a lot more appealing.

Also a box below or beside the main frame that displays descriptions of the different buttons’ functions when the buttons are hovered over would be cool.

I know it’s open source, but I don’t have time to do anything rn so I’m just putting that out there.

Sure, I’ll start working on that right away!

1 Like

Updates added!!!

1 Like

Update:

The plugin is now available for purchase as free! Get it here:
StudioSort Pro - Creator Store

1 Like

Currently working on one of the planned improvements I listed which was One click sorting of entire services.

Expect it to be done by Monday but it might be delayed. (If it is I’ll make a notice.)