Articles › Game development

Roblox Server Authority: stop cheaters with client prediction and rollback

Roblox Server Authority is live for every game: the server owns state, clients predict and roll back when wrong. How to turn it on, write code for it, and its limits.

Intermediate 6 min read October 23, 2026

What you will learn
  • With Server Authority the server owns game state and clients only send input, so speedhacks and flyhacks fail by design
  • Clients predict a few frames ahead; when the server disagrees they reset to its state and resimulate the remaining frames
  • Turn it on with Workspace.AuthorityMode = Server, move core logic into RunService:BindToSimulation and read input through InputAction
  • Use time(), not tick() or os.clock(), because simulation time has to rewind during resimulation

If your Roblox game lets each client move its own character, a cheat program can move it too: too fast, through walls, into the air, because the server trusts the position the client reports. Server Authority, released for all games on 9 July 2026, flips that trust. The server owns the game state, clients send only their inputs, and client prediction hides the latency. This article covers the mechanism, how to switch it on, how to write code that fits it, and the traps.

Facts checked against the Server Authority page on the Creator Hub, the Full Release post on the DevForum (9 July 2026) and the BindToSimulation release post (29 April 2026), as of October 2026.

If you are not sure which code runs where yet, read Roblox EP3: server and client first; this builds on it.

How it worked before, and why cheating was easy

In the classic Roblox model, a player’s character has network ownership on that player’s machine. The client computes its own physics and sends the result up. You press a key and the character moves instantly, but the server has to believe the result. Anti-cheat meant writing after-the-fact checks, such as measuring distance per second and snapping players back, which is fiddly and easy to get wrong.

Server Authority makes the server the single source of truth. Clients send inputs only (move forward, jump) and the server simulates the outcome. A cheat that edits speed on its own machine has no effect on the real state.

Client predicts aheadfeels instantServer state arrivesCompare the same frameMismatch: roll backResimulate to now
The client may guess; the server's state always wins

Prediction, misprediction, rollback

Waiting for the server on every key press would make a 100 ms player feel lag on every input, so the client predicts:

  1. Prediction: the client simulates several frames ahead of the last server-confirmed state, using its own inputs. How many depends on latency
  2. Compare: when the authoritative state for a frame arrives, the client compares it with what it predicted for that same frame
  3. Misprediction: they differ (latency changed, another player bumped you, server-only logic ran)
  4. Rollback + resimulation: the client resets to the server’s state and replays the frames up to now, reapplying its own inputs

The docs’ example: a client two frames ahead mispredicts frame 3, so it resimulates frames 4 to 6 before frame 7. The player may see the character jump to the correct spot.

The client may guess, but it never decides. On every misprediction the server’s state wins.

Worked example: what a rollback costs

The frames-ahead count and per-step cost below are estimates to make the point; the docs give no formula.

  • BindToSimulation at Enum.StepFrequency.Hz60 → one step = 1000 ÷ 60 ≈ 16.7 ms
  • A player with 100 ms round trip → roughly 100 ÷ 16.7 ≈ 6 frames ahead
  • Assume our callback costs 1 ms per step
  • One misprediction → 6 steps × 1 ms = 6 ms of resimulation inside one frame’s 16.7 ms budget

At 3 ms per step that becomes 18 ms, already over a frame, and low-end devices drop frames. The lesson: everything in BindToSimulation can run again. Keep only logic that decides the outcome there; move cosmetics (sounds, effects, decorative animation) to RenderStepped.

Turning it on

In Studio, open Workspace properties, Server Authority section, and set AuthorityMode to Server. The rest follows automatically:

PropertySet toWhat it means for you
NextGenerationReplicationEnabledthe new replication system
PlayerScriptsUseInputActionSystemEnabledPlayerScripts use InputAction
SignalBehaviorDeferredevents fire at the next resumption point, not immediately
UseFixedSimulationEnabledinternal systems (Humanoid, animation, ControllerManager) run at a fixed rate
StreamingEnabledEnabledparts of the map far from the player may not be loaded on the client

Then save and publish. If your game did not use StreamingEnabled before, that is the biggest change: client code that grabs workspace.Map.Door directly must wait for it to stream in.

UseFixedSimulation is the same idea as a fixed timestep game loop: every machine advances time in equal steps, so results can be compared.

Writing code for the simulation

The pattern from the docs: core logic lives in a ModuleScript initialised on both server and client, inputs come from InputAction, your own state goes in attributes, and attributes on predicted instances are written only inside BindToSimulation.

The sketch below is a Boost button that drains stamina. Create an InputContext named GameplayContext with a Bool InputAction named Boost in ReplicatedStorage.

-- ServerScriptService/GiveInputContext (Script)
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

Players.PlayerAdded:Connect(function(player)
	-- an InputContext must be a descendant of the Player
	ReplicatedStorage.GameplayContext:Clone().Parent = player
end)
-- ReplicatedStorage/Simulation (ModuleScript)
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local MAX_STAMINA = 100
local DRAIN_PER_SEC = 40
local Simulation = {}

function Simulation.Initialize()
	RunService:BindToSimulation(function(dt)
		-- the server simulates everyone; a client predicts only its own character
		local list = if RunService:IsServer() then Players:GetPlayers() else { Players.LocalPlayer }
		for _, player in list do
			local character = player.Character
			local context = player:FindFirstChild("GameplayContext")
			if not (character and context) then continue end

			local boosting = context.Boost:GetState() == true
			local stamina = character:GetAttribute("Stamina") or MAX_STAMINA
			if boosting and stamina > 0 then
				stamina = math.max(0, stamina - DRAIN_PER_SEC * dt) -- always clamp
			end
			character:SetAttribute("Stamina", stamina)
		end
	end, Enum.StepFrequency.Hz60)
end

return Simulation

Call require(ReplicatedStorage.Simulation).Initialize() from both a Script in ServerScriptService and a LocalScript in StarterPlayerScripts. The client gets an instant result, the server holds the real value, and if the attribute differs between the two, the engine rolls back for you.

This follows the pattern in the docs; before shipping, compare it with Roblox’s Racing, Soccer or Laser Tag server authority templates.

Rules to remember

  • Time: use time(), the fixed-step simulation time that rewinds and replays. tick(), os.time() and os.clock() are not synchronised and do not roll back
  • Input: every input that affects the simulation goes through InputAction, never UserInputService.InputBegan; validate values before use
  • Attributes: only the first 64 per instance replicate, names up to 50 characters, string values up to 50 characters
  • APIs inside the simulation: only properties and methods labelled “Simulation Access”. task.spawn() from a callback keeps those restrictions; task.defer() escapes them
  • Camera: Camera InputAction no longer synchronises; use Player:GetCameraState(), which returns CFrame, FieldOfView and ViewportSize

Common mistakes

  • Playing sounds or effects in BindToSimulation. A rollback plays them again; move them to RenderStepped
  • Timing cooldowns with os.clock(). It does not rewind during resimulation, so cooldowns drift; use time()
  • Treating RemoteEvents as part of the timeline. Their order relative to properties and attributes is not guaranteed, and a reply in the release thread reports them landing about 40-50 ms off. Use them for discrete events only
  • Switching on and publishing straight away. Test with Studio’s Network Simulation at high latency and packet loss first
  • Ignoring the early limits. The Full Release post lists eight actively playing tracks per Animator, and changing Tools during a misprediction may delete the Tool’s Weld on the client. Check the current known limitations before switching

Sources

FAQ

Will turning it on break an existing game?

It can. It also forces StreamingEnabled, Deferred signal behaviour and the InputAction system. Code that relies on UserInputService, or assumes the whole map is always loaded on the client, needs changes. Always try it in a copy of the place first.

Do I still validate RemoteEvents myself?

Yes. Server Authority covers what runs in the simulation. RemoteEvents for discrete actions such as purchases still need permission and value checks on the server, and they are not ordered with the simulation timeline.

Will it cost more server CPU?

Roblox says server utilisation will increase, by how much depending on how close your game already is to the limit. Measure in Studio before switching on in production.

Commands and settings were tested on sample systems. Try them on a test machine before production.