Shared

Maid

Lifecycle cleanup utility. Track connections, threads, instances, and teardown functions — then clean them all up at once. Works with any object that has a natural teardown.

Create local maid = RoExpress("Maid")

Each call to RoExpress("Maid") returns a fresh Maid instance. The Maid module itself is also accessible as RoExpress.Maid if you need the factory directly.

Add

local conn = maid:Add(item)  -- returns item unchanged

Track an item for cleanup. Returns its argument unchanged so you can store and track in one expression:

local conn = maid:Add(Bridge.On("kill", handler))
-- conn is still typed as BridgeConnection
conn:Disconnect()  -- or let maid:Destroy() handle it

Maid handles the following item types automatically:

TypeWhat Maid calls
RBXScriptConnection:Disconnect()
Any table with Disconnect:Disconnect() — covers BridgeConnection
Any table with Destroy:Destroy() — covers Instance, nested Maid
thread (coroutine)task.cancel()
functionCalled with no arguments — arbitrary teardown

Remove

maid:Remove(item)

Immediately clean and stop tracking a specific item. Useful when an item's lifetime ends before the Maid is destroyed.

Clear

maid:Clear()

Clean all tracked items and reset the Maid to empty. The Maid itself remains usable — you can continue adding items after a Clear. Useful at the end of a round or phase when you want to reuse the same Maid.

Destroy

maid:Destroy()

Clean all tracked items and make the Maid inert. Do not use the Maid after calling Destroy. For module shutdown or when the owning object is destroyed.

Nesting

Maids can be nested. A child Maid added to a parent Maid will have its own :Destroy() called when the parent is destroyed — useful for per-player or per-round sub-lifecycles.

local gameMaid   = RoExpress("Maid")
local roundMaid  = gameMaid:Add(RoExpress("Maid"))

roundMaid:Add(Bridge.On("round.tick", onTick))
roundMaid:Add(Bridge.On("round.end",  onEnd))

-- end of round: clean round events, keep game events
roundMaid:Destroy()

-- full shutdown: cleans everything including gameMaid children
gameMaid:Destroy()

Gun equip / unequip

A common pattern — create a Maid when a tool is equipped and destroy it when unequipped so all connections are always cleaned up, even with anonymous handlers.

local maid: RoExpress.Maid

tool.Equipped:Connect(function()
    maid = RoExpress("Maid")

    maid:Add(Bridge.On("ammo.refill", function(data)
        ammo = data.amount
    end))

    maid:Add(UserInputService.InputBegan:Connect(function(input)
        if input.UserInputType == Enum.UserInputType.MouseButton1 then
            shoot()
        end
    end))

    maid:Add(function() print("gun unequipped") end)
end)

tool.Unequipped:Connect(function()
    if maid then maid:Destroy() end
end)

See also

Bridge | BridgeConnection returned by Bridge.On / Bridge.Once  ·  Hook | Roblox signal subscriptions also return connections  ·  Debounce | cooldown wrappers