The SUNC cache library
Roblox caches its instance references in a C-level lookup table. That cache is invisible to most scripts, but when you're doing anti-detection work or trying to give a function an alternate identity, you need to manipulate it. The SUNC cache library is how you do that.
Why a cache exists at all
Every time a script accesses a Roblox instance — say, game:GetService("Players") — the engine could create a fresh Lua userdata value, but that would be wasteful: the same service would have a different identity on every call. Instead, Roblox interns instances in a C-side cache keyed by the underlying object pointer. The first lookup creates the Lua-side handle, every subsequent lookup returns the same one.
That's why game:GetService("Players") == game:GetService("Players") is reliably true. It's also why an instance that gets destroyed and recreated will (usually) produce a different Lua handle on lookup — the cache entry was invalidated when the C object went away.
cache.iscached
The simplest entry point. Asks: is this instance currently in the cache?
cache.iscached(instance: Instance): booleanbooleanprint(cache.iscached(game.Workspace)) --> trueYou almost never call this in isolation. It's most useful as a debugging tool when you've been calling cache.invalidate and want to confirm the invalidation actually landed.
cache.invalidate
Remove an instance from the cache. The instance still exists in the underlying C engine; what changes is that the next Lua lookup of the same C object will create a new Lua handle instead of returning the old one.
cache.invalidate(instance: Instance): ()voidlocal players = game:GetService("Players")
cache.invalidate(players)
local fresh = game:GetService("Players")
print(players == fresh) --> false (different Lua handle for the same C object)This is the trick that creates two distinct Lua values for the same underlying instance. players and fresh point at the same Roblox service, but Lua equality is false. Useful when you want to hold onto a "hidden" reference that won't equal anything the game subsequently retrieves.
cache.replace
Substitute one instance for another in the cache, so that lookups for the original return your substitute instead.
cache.replace(original: Instance, replacement: Instance): ()voidlocal fake = Instance.new("Folder")
cache.replace(workspace.RealFolder, fake)
print(workspace.RealFolder == fake) --> trueThis is the heavier sibling of invalidate. Use it sparingly: it changes what the rest of the script sees from a fundamental data-model lookup, so any code that walks the workspace will get the replacement instead of the real instance.
cache.clonefunction (cloneref)
The most commonly-used cache primitive in real scripts is cloneref — sometimes spelled cache.clonefunction in older docs, butcloneref in SUNC. It returns a new Lua handle pointing at the same underlying instance, without invalidating the cache.
cloneref(instance: Instance): InstanceInstancelocal players = game:GetService("Players")
local alias = cloneref(players)
print(players == alias) --> false
print(alias.LocalPlayer == players.LocalPlayer) --> trueThe everyday use case: keep a private reference to a service that the game can't fingerprint against the cached version. You can stash cloneref(game:GetService("CoreGui")) at script startup; later, if the game replaces the cached CoreGui (or hooks identity comparisons against it), your alias still works.
compareinstances: identity-safe comparison
Because cloneref makes == unreliable for "is this the same instance" checks, SUNC ships a dedicated comparator.
compareinstances(a: Instance, b: Instance): booleanbooleanlocal a = game:GetService("Players")
local b = cloneref(a)
print(a == b) --> false
print(compareinstances(a, b)) --> trueUse compareinstances any time your script needs to check "is this the same Roblox object?" without worrying about which handle each variable holds.
A real-world pattern: hidden gui parents
Here's a classic combined use of cloneref and cache.invalidate. The goal: parent a UI under CoreGui without leaving traces that the game can enumerate.
local coreGui = cloneref(game:GetService("CoreGui"))
local screen = Instance.new("ScreenGui")
screen.Name = "_" -- intentionally empty-looking
screen.Parent = coreGui
screen.ResetOnSpawn = false
-- The game enumerates game:GetService("CoreGui"):GetChildren().
-- That call returns the cached CoreGui, whose children are scanned —
-- but our alias was cloned, so this code path doesn't expose the alias
-- as a fingerprintable identity for our screen.The combination matters because both coreGui and the cached CoreGui still refer to the same instance — so the screen is genuinely parented there. The handle our script holds is just a separate Lua-side view of it, which is enough to avoid certain identity-based detections.
What the cache doesn't protect you from
It's tempting to think of cloneref as invisibility, but it isn't. A game that walks :GetChildren() on the parent still sees your instance — handles are about identity, not visibility. If you parent something under CoreGui, it's findable by anyone who walks CoreGui's children. The cache library helps with identity comparisons; concealment is a separate problem.
Wrap-up
The cache library is small but it sits between Lua and a C-side detail most scripts never touch. Use cloneref for private aliases, cache.invalidate when you want subsequent lookups to produce a fresh handle, and compareinstances any time identity matters. cache.replace is the nuclear option — useful, but rarely needed.
Ather is the lead developer behind Atherhub. He's been writing Luau and Roblox tooling for the better part of a decade, with a focus on the messy interface between game-script internals and the platforms that host them. Have feedback on this article? Drop it in the Discord.