12 min read

Source: Roblox Creator Hub · CC BY 4.0 · View source · Code samples: MIT Imported 2026-10-03. Formatting adapted for this site.

Script capabilities

Note

Script capabilities are experimental and available as a client beta.

Script capabilities let you control which actions scripts can perform inside the DataModel subtree. Rather than the default "all-or-nothing system," you can set a script to only be able to access certain categories, such as audio, physics, data stores, and more.

Enable script capabilities

To enable this feature, change the SandboxedInstanceMode property from Default to Experimental in the Explorer and Properties window.

Sandboxed container

Script capabilities introduces a concept of a sandboxed container. Models, Folders, Scripts, or descendants of any of those classes have a Sandboxed property available in the Properties window.

Sandboxed property of a Folder in the Properties window.

Enabling the Sandboxed property designates the instance as a sandboxed container inside the DataModel tree, which limits the actions that the scripts inside that container can perform based on the set of values in the Capabilities property.

Capabilities

The Capabilities property is a set of values that control different aspects of execution. Capabilities fall into the following broad categories:

When a script attempts to perform an action that is not in the set of capabilities, Roblox reports an error. Errors typically include the action being attempted, the target of an action, and the first capability that is missing:

The current thread cannot modify 'Workspace' (lacking capability AccessOutsideWrite)
The current thread cannot call 'Clone' (lacking capability CreateInstances)
The current thread cannot call 'GetSecret' (lacking capability Network)

Execution control

Two capabilities handle execution control:

If the script is Enabled, but the capability corresponding to the location it attempts to start in is not available, a warning message is displayed in the Output window. If a script wasn't supposed to run in that context, disable or delete it.

Note that ModuleScripts do not need to have these execution capabilities to be required.

When a script fails to start because the execution control capability is missing, it is reported as a warning in the output, for example:

Cannot start server script 'Script' (lacking capability RunServerScript)

Instance access control

A single capability handles instance access control:

When the capability is not available, the script can only look up instances that are inside its own sandboxed container. For example, if the script is placed directly in the sandboxed container, script.Parent.Parent returns nil.

Additionally, any Roblox API event that passes in an Instance instead passes in nil for any Instance outside the sandboxed container. For example, if the BasePart.Touched is signaled by a touch from an instance outside the sandboxed container, the event is still received, but the argument is nil.

Avoid setting this capability; sandboxing guarantees are weaker when scripts can interact with any instance in a game.

Access to services

Even without AccessOutsideWrite, scripts in the sandboxed container can still access game, workspace, and services. This access is provided so that scripts can still call useful methods of those globals, like DataModel.GetService, but access to their child instances is still validated.

Internally passed instances

If an instance is passed through a function call that doesn't go through Roblox APIs, the reference is preserved. However, if a ModuleScript is passed in this way, it can't be required without AccessOutsideWrite. This is because the return of the ModuleScript is often mutable and can be modified by a script in a sandboxed container.

Script functionality control

This set of capabilities controls some general aspects of scripts:

Keep in mind that default function restrictions still apply. Even if LoadString is enabled, the game still has to enable it in ServerScriptService, and it is still only available on the server.

To create new instances, aside from CreateInstances, an additional Engine API capability providing access to that instance is required.

Engine API access control

This last group of capabilities controls script access to various Engine APIs:

The capabilities of each class, property, method, and event are displayed in the Engine API reference. For example, Player:GetFriendsOnlineAsync() requires the Player and Social capabilities.

Several HttpService methods are available without any capabilities aside from being able to execute the scripts:

If an instance property or method is accessed without a required capability, an error is reported describing the missing capability.

Finally, capabilities do not cover every instance in the Roblox Engine today. Instances not listed in this section or the following one are not available for interaction from a sandboxed container and throw an error saying that an Unassigned capability is not available to the current script.

An additional limitation is that LuaGlobals.getfenv() and LuaGlobals.setfenv() functions are not available for scripts in a sandboxed container. Calling them from a sandboxed script reports:

The current thread cannot call ['getfenv'/'setfenv'] - the target uses APIs not available in the current sandbox

Only script access to instances is limited. The instances themselves can still exist and operate by themselves inside a sandboxed container. Lights still shine, user interfaces are still visible, and audio setups that are already wired play sounds.

Interactions between containers

Nested containers

When one sandboxed container is nested inside another one, the instances of the inner container are accessible to the outer one.

Capabilities of the inner container are limited by the capabilities of the outer one. For example, if the outer container has capabilities of Basic, Audio and CSG, while the inner container has Basic and Network, only Basic capabilities are available to the inner container at runtime.

If there are no capabilities in common between the inner and outer containers, the resulting capability set is empty.

Bindable functions and events

BindableEvent and BindableFunction provide the best way to communicate with the container or allow it to run callbacks with capabilities it itself is not allowed to use directly.

When an event is fired or a function is invoked, connections are executed in the context of the function that registered them. This means that if the event or function callback is registered by the sandboxed container, it is called with the capabilities of that container. If the callback is registered by the code outside, when sandboxed container scripts invoke them, they execute your functions with capabilities available to your functions.

It is important to note that even with the AccessOutsideWrite capability, scripts in sandboxed containers cannot invoke events or functions outside their containers if they have a larger capability set than the container itself.

When a sandboxed script tries to fire or invoke an event or function (BindableEvent, BindableFunction, or RemoteEvent) whose ancestor capabilities exceed its own, the error names the property to inspect.

If the target is not inside any sandboxed container:

The current thread cannot fire '<Target>' since '<Target>' has the Sandboxed property set to false but the calling thread is sandboxed

To resolve this, set Sandboxed to true for the target. Alternatively, you can modify the source of the calling thread to have Sandboxed set to false, but this is not recommended as it eliminates the security benefits sandboxing provides.

If the target is sandboxed but has capabilities the caller lacks:

The current thread cannot fire '<Target>' since '<Target>' has additional values for the Capabilities property: <First Missing Capability> (and N more)

To resolve this, narrow the target's Capabilities to a subset of the caller's, or expand the caller's Capabilities to match the target's.

Module require

Inner ModuleScripts can be required by the sandboxed container as usual. However, if the target instance is outside the container, the ModuleScript can only be required if the capability set that is available to it is smaller or equal to the capabilities available to the container.

This limitation does not apply to RunClientScript and RunServerScript capabilities. If the ModuleScript is placed in a container with only RunClientScript but is required from a script that has the RunServerScript capability, it is allowed to succeed and run those functions on the server.

When LuaGlobals.require() fails on a capability mismatch, the error names the target module and the property to inspect in the same manner as Bindable functions and events described in the previous section.

Directly called functions

If a ModuleScript in a sandboxed container is required from outside the container, some of the protections are not available. In particular, the target function is able to access all instances available to the caller. If the caller is not in a sandboxed container, the call acts as if AccessOutsideWrite is available to it.

Other capability restrictions still apply. If you have a DataStore access capability, but the target module does not, it is unable to call DataStore methods. However, if you pass your own function working with DataStore, the target can run it during that call. If the target schedules a thread using methods like those from task, those threads lose the ability to call that function.

Instances can be passed to the target module or assigned to the module fields.

If required, it is recommended to assign table members using LuaGlobals.rawset to avoid running __index/__newindex metamethods that might be set on the table.

The overall recommendation is to communicate with BindableEvent and BindableFunction whenever possible.

Movement of instances

Most instances do not have restrictions on movement between containers. Script instances, however, can only be moved into a container that has the same set of capabilities or a subset of those capabilities.

This means that a sandboxed container with AccessOutsideWrite cannot just re-parent a script inside itself to outside and get more capabilities.