TLDR:
- This post will evolve a bit over time
- This is a minimum set of initial APIs that will be expanded upon.
- Even smaller than Early Access
- We will expand the APIs during the lifetime of the Studio beta
- Always easier to expand APIs (instead of reducing) without negatively impacting Roblox Creators
- Default Avatars should just work, and easily customizable
- Functionality is focused around scripts that have control loops that are bound to RunService::BindToSimulation
- Currently the system works best with simple, one-assembly mechanisms
- Complex mechanisms (cars with suspensions, ETC) still work with the API but experience quality will most likely be reduced
- There is quite a bit of work on our part to improve this
- Some notes on two required features to enable Server Authority
- Deeper dive on some of the Known Issues
Hi everyone!
Thanks for being interested in the Server Authority beta, this is something that many of us have dreamed of having on the platform for many years, and being so close to a first release has us extremely excited!
We wanted to take a moment to set up some expectations for the initial Server Authority Studio Beta. Some of you may know that once an API is in Roblox, itās in Roblox forever-ish. Because of this, the current beta is the MINIMUM set of APIs that we feel confident about. This does mean that this is not a complete and final API. Weāve spent a lot of time removing one off hacks that enabled the Early Access Beta APIs, throughout the Roblox engine, allowing us to ship the Server Authority Studio Beta built upon a sustainable core tech stack. This initial API unlocks a lot of Server Authoritative content, so we want to get it in Creators` hands ASAP for further testing and feedback!
We expect that as you start developing some content you will run into pain points and will want to request API extensions. This is part of the process and we want your feedback so that we can methodically extend the capabilities of Server Authority before the fully playable launch in early 2026. We have internally verified the existing API by writing movement abilities for player characters, simple sports games, racing experiences, and shooting games, but these are going to be much simpler experiences than anything you will build, which is why the feedback will be key. The most effective way to request new features is to describe your use-case in detail! Another callout is that we have been mostly focused on feature completeness, so expect performance to significantly improve before the initial launch for Server and Clients.
The current Server Authority technology has been built and optimized primarily for simple mechanisms, like the player characters/avatars. When opted into the Server Authority Studio Beta, if you open a baseplate and change Workspace.AuthorityMode to Server (There may be some pieces of core tech you may need to enable first) and hit play, you will be playing on Server Authoritative default character avatar without writing any code. āIt just works(
)ā.

Just because weāve been focusing on simple mechanisms and avatars doesnāt mean that you canāt start experimenting with more complex systems. You can add your own capabilities to default avatars by using module scripts that have a loop bound via RunService:BindToSimulation, and Server and Client bootstrapper scripts that initialize the control loops. Additionally, more complex mechanisms like cars could also be used with the beta today, but we havenāt done the full pass on reducing mispredictions/jitter when working on more complex mechanisms. The Roblox engine was never built with the determinism that makes Server Authority work well, so more complex mechanisms are increasingly more likely to feel ājitteryā in this initial Server Authority beta. We are working on this!
Server Authority Requirements
You may have noticed the list of required technologies that have to be enabled before Server Authority is toggle-able, and we want to take some time to highlight a few of these.
Workspace.NextGenerationReplication
This is a brand new replication architecture that weāve been working on at Roblox for a few years now, and itās one of the key pillars that make Server Authority on Roblox possible. For Server Authoritative gameplay to be responsive the Server has to send the most relevant updates to each player frequently.
The legacy Roblox replication system was not capable of this:
- Properties would replicate via a pseudo āFirst In First Outā principle, where an update to Color on a tree two miles away would be sent before an update to a Weld CFrame on a mechanism right next to a player just because the Color update happened first during a script call.
- Additionally, Properties would be sent reliably and could block future updates under certain networking conditions
- Physics updates on moving objects WOULD actually be prioritized and sent based on relevancy
- Physics updates were unreliable by default and would never block future updates
- So imagine a scenario where you have a lot of script-driven property updates, including one that updates a mechanismās weld CFrame and then simulation that moves the mechanism as a whole. This kind of update almost always arrives desynchronized from Server to Clients due to the wildly different natures of the Physics and Property replication systems.
The new system aims to address these issues and unify the best parts of both replication methods: We get prioritization for the vast majority of networked data, while also making sure that Instance updates are significantly more likely to be synchronized.
With NextGenerationReplication set to Enabled if you are constantly updating the state of the objects in the game world via scripts or simulation, each player will receive the higher priority updates more frequently. You can use the image above to visualize how this would work. If the red dot at the center is a player, then all of the items in the āgreenā zone are being updated more frequently and are considered higher priority, while things further out in the orange and red zones will be prioritized less frequently.
This prioritization and synchronized sending is part of what lets us be able to use prediction and validation on the Clients to maintain a responsive gameplay loop even when the true simulation happens on the Server.
Attribute Limits
Part of what makes Server Authority work is making sure payloads for synchronization to the server are quick and timely. This requires us to fit things into a single MTU as much as possible. This is fairly easy to guarantee with Roblox instance Properties since they are normally small and hard capped, however user defined payloads are more complicated.
For now we have strict limits on Attribute Replication to make sure they are small payloads that can be synchronized efficiently. In the future we plan to loosen these, but it requires some feature design and extra architectural expansion.
Important Callouts
- Larged/Uncapped properties will still use legacy replication, things like Strings, Arrays, ETC.
- There are no more ordering guarantees for property updates! This breaks the guarantee that when a RemoteEvent arrives that all properties that were updated BEFORE the event was sent would have replicated.
- Server Performance with 20+ player games needs a lot of work!
Workspace.StreamingEnabled
NextGenerationReplication does a lot of extra CPU work on the Server that didnāt exist before, since we are prioritizing all Instance property updates (something we didnāt have to do with FIFO logic before). Streaming provinces a necessary scalability limit on how much prioritization work needs to happen on the Server. Itās also a key requirement for how we plan to make Server Authority work on low-end devices.
Additionally, RunService::setPredictionMode relies on atomicity/instance grouping that only exists in Streaming. (note: this may not be fully enabled on the first beta version) There are other core functionalities from streaming that we depend on under the hood, and not all of them are currently enabled.
Known Issues
Finally, we want to mention again that since our goal with this Studio Beta is to get the initial API in front of as many developers as possible, we do want to mention that there are still some known issues and initial limitations that will be addressed before the full playable release, including some security issues that will be addressed.
API Behavior that will change before full release:
- RunService::setPredictionMode currently only applies overrides to the specific instance it is called on. In the future, this will work similar to :SetNetworkOwner where prediction will be applied to the NOU or Atomic Model. (Internally we call this grouping āStreaming Setsā)
- RunService::getPredictionStatus will work correctly even with Workspace::AuthorityMode == Automatic so that any vehicles/control scripts you create for Server Authoritative experiences will be compatible in non-server authoritative experiences.
- We are missing a āRunService::OnRollbackā event that lets creators reset custom state when mispredictions must be corrected
- Properties/Data settable via RunService:BindToSimulation is not finalized
Some Extra Callouts/Workarounds on Specific Known Issues
This is diving a bit deeper into some of the known issues called out in the main announcement thread.
Instance creation and deletion
New instances must be created on the server outside of the Simulation loop. Creators can use a deferred task, BindableEvent, or a BindableFunction to create new instances or destroy existing instances.
Creating a new Part on the Server in a deferred task
RunService:BindToSimulation(function(deltaTime)
if RunService:IsServer() then
task.defer(function()
local newPart = Instance.new("Part")
newPart.Parent = game.Workspace
end)
end
end)
Deleting a part on the Server in a deferred task
RunService:BindToSimulation(function(deltaTime)
if RunService:IsServer() then
task.defer(function()
game.Workspace.SomePart:Destroy()
end)
end
end)
The server only replicates changes
Clients can diverge from the server and not be resynchronized if a change only takes place on the client and no changes take place on the server; the server only replicates data to the clients when changes are made. If nothing changes on an instance, its data will not be replicated to the clients.
For example, if a client mispredicts that a point was scored by incrementing an attribute, the client might not be corrected until the server changes the instance that holds the attribute. This is the expected behavior for Roblox replication, but might be unexpected in a place designed around server authority. You can force replication on an instance by changing one of its attributes on the server:
Forcing the constant replication of an Instance
RunService:BindToSimulation(function(deltaTime)
if RunService:IsServer() then
local alwaysReplicated = game.Workspace.Part
alwaysReplicated:SetAttribute("Time", time())
end
end)
IF YOU HAVE TO USE THE ABOVE TRICK, PLEASE SEND US A REPRO AS THIS IS A FUNCTIONALITY GAP!
Input change signals are inaccurate during rollback
When a clientās simulation is rolled back to an authoritative server state, InputActionsā Change signals can be fired. These signals will happen at different frames than they will on the server, which can result in incorrectly detected inputs on the client.
Instead of using InputAction:Changed, InputAction:Pressed or InputAction:Released, poll InputAction:GetState() in BindToSimulation.
If input changes (like new key presses) are needed, store the InputActionās last state as an attribute of a predicted instance, and compare the current state to the attribute to detect changes within RunService:BindToSimulation().
Detecting new inputs using Attributes
RunService:BindToSimulation(function(deltaTime)
for _, player in Players:GetPlayers() do
local hrp:BasePart = player.Character.HumanoidRootPart
local inputContext:InputContext = player.PlayerGui.InputContext
local shootInput = inputContext.ShootAction:GetState()
local previousShootInput = hrp:GetAttribute("ShootInput") or false
hrp:SetAttribute("ShootInput", shootInput)
if shootInput and not previousShootInput then
shoot(player)
end
end
end)
BasePartās Touched signal is inaccurate during rollback
When a clientās simulation is rolled back to an authoritative server state, BasePartās Touched and TouchEnded events can be fired if a BasePart is rolled back to a touching or not touching state. These signals will inaccurately fire on the client when they might not have fired on that frame on the server.
To ensure consistent behavior between client and server, use BasePart:GetTouchingParts() in RunService:BindToSimulation(). If new touches need to be detected, write the relevant information to attributes on a predicted instance to record the necessary information to detect new touches.
Detecting new contacts with the ground
RunService:BindToSimulation(function(deltaTime)
for _, player in Players:GetPlayers() do
local hrp:BasePart = player.Character.HumanoidRootPart
local isOnGround = false
local isTouchingGround = false
local touchingParts = hrp:GetTouchingParts()
for _, p in touchingParts do
if p.Name == "Ground" then
isTouchingGround = true
break
end
end
-- Check if we were on the ground last frame
local wasOnGround = hrp:GetAttribute("OnGround") or false
-- Update OnGround attribute for next frame
hrp:SetAttribute("OnGround", isTouchingGround)
if isTouchingGround and not wasOnGround then
-- player newly touched the ground
game.ReplicatedStorage.TouchedGroundEvent:Fire(player)
end
end
end)
Seats are client authoritative
Seats and seat welds have client authority in Roblox. Seats can be sat in by any player, at any time, no matter the distance. Players can exploit seats by sitting in them as a way to teleport. Seat welds in Roblox are implicitly owned by the player who sits in the seat and they can be created and destroyed by the client. Using default seat weld systems can create desynchronization where the client thinks they are still in the seat, but the server does not, or vice versa.
Humanoid Enabled States do not Replicate
Setting humanoid states to enabled or disabled does not replicate between client and server. Calling Humanoid:SetStateEnabled() will not replicate any data between client and server meaning deviations between the two will not be rectified. You can fully synchronize enabled states by storing their data in Attributes and setting them every frame.
Synchronizing the ability to Jump with an Attribute.
RunService:BindToSimulation(function(deltaTime)
local canJump = humanoid:GetAttribute("CanJump")
humanoid:SetStateEnabled(Enum.HumanoidStateType.Jumping, canJump)
end)
Setting the PredictionMode on a nil Instance will crash
Calling RunService:SetPredictionMode() with nil will crash. This will be fixed in the next release. Creators should check for nil before calling SetPredictionMode() in their scripts.
-- This will crash!
RunService:SetPredictionMode(nil, Enum.PredictionMode.On)
-- Check for nil in Luaua for safety:
if instance ~= nil then
RunService:SetPredictionMode(instance, Enum.PredictionMode.On)
end
