---
title: "Server authority model"
url: /docs/en-us/projects/server-authority
last_updated: 2026-10-30T19:55:54Z
description: "The server authority model lets you build responsive cheat-free competitive games such as FPS, racing, sports, and combat."
---

# Server authority model

In a **server authority model**, the server is the single **source of truth** for the entire game state, and clients are only trusted to report their own inputs. This architecture is the core netcode foundation of a fair, competitive game because it prevents entire classes of cheating like flyhacks or speedhacks by never trusting a client to report its own position or state.

## Advantages

In a naive server-owned system, clients would simply send their inputs to the server and display the results of the game sent back by the server. While technically correct, such a system would face significant **input latency** because every player action would have to travel to the server, be processed, and have the result sent back to the client before it could be displayed. For most games, especially those fast‑paced, that round‑trip delay would cause gameplay to feel laggy, unresponsive, and unplayable.

In Roblox's **server authority** model, latency is compensated for by having clients instantly [predict](#client-prediction) the effects of their inputs in addition to sending them to the server. For example, when a player presses a key, the client doesn't wait for the server to respond; instead it **predicts** a few frames ahead of the last known server state. This allows the client to show the result of the input action instantly, effectively hiding network latency and making the game feel responsive.

Sometimes the client will get its prediction wrong ([misprediction](#client-misprediction)) and, because of network latency, the client will not know that it has made a mistake for a few frames. For example:

> **Warning:** Your client predicts that you've moved forward, but on the server another player used a stun ability that stopped you from moving. The client and server now have different states.

When a misprediction is detected, the client must correct its prediction based on the server's **authoritative state**. If the authoritative state is different from the client's predicted state, the client must [roll back and resimulate](#rollback-and-resimulation) its predicted frames. This system of client‑side prediction, rollback, and resimulation is known as "latency compensation" and helps make server‑authoritative multiplayer games feel smooth and responsive.

> **Info:** Mispredictions are a **normal and expected** part of the server authority architecture because clients inherently cannot predict other players' inputs, so actions by other players will always trigger some amount of misprediction. When tuned correctly, the resulting corrections are small and should be imperceptible to players. Read further on [advanced techniques](/docs/en-us/projects/techniques.md) to smooth out and mask network artifacts.
## Setup

The server authority model requires certain other engine technologies to function correctly. Confirm the following property settings on the `Class.Workspace` object in the [Explorer](/docs/en-us/studio/explorer.md):

1. `Class.Workspace.AuthorityMode` must be `Enum.AuthorityMode.Server|Server` (setting this automatically sets the following five).
2. `Class.Workspace.NextGenerationReplication` must be enabled.
3. `Class.Workspace.PlayerScriptsUseInputActionSystem` must be enabled.
4. `Class.Workspace.SignalBehavior` must be `Enum.SignalBehavior.Deferred|Deferred`.
5. `Class.Workspace.UseFixedSimulation` must be enabled.
6. `Class.Workspace.StreamingEnabled` must be enabled.

## Concepts

The server authority system runs on a few core concepts as follows.

### Client prediction

Through **client prediction**, the client simulates a few frames ahead of the last known server state to predict the effects of player inputs immediately. This hides input latency, but the prediction may later turn out to be incorrect ([client misprediction](#client-misprediction)) and thus require correction. The client tries to simulate just far enough ahead of the last known authoritative server state so that its inputs arrive on the server at the intended frame. The number of frames the client will predict ahead of the known server state is based on the latency behind the client and server.

### Client misprediction

When the client receives the authoritative state from the server, it checks that state against a historical record of what it predicted locally for that frame. When there is a difference between what the client [predicted](#client-prediction) and what the server actually did, this is a **misprediction**. Mispredictions can occur for several reasons, including shifts in network latency, other players acting in ways the client didn't anticipate, the game running certain logic exclusively on the server, etc.

If the authoritative state is different from the client's predicted state, the client must [roll back and resimulate](#rollback-and-resimulation).

### Rollback and resimulation

When a client detects a [misprediction](#client-misprediction), it must reset to the server's authoritative state and then resimulate to jump back to its predicted frame. Based on the network latency, the client tries to simulate just far enough ahead of the last known authoritative server state so that its inputs arrive on the server at the intended frame.

```mermaid
block-beta
columns 1

    block:Client
        columns 7

        ClientHeader("<span style="color:white;"><b>Client</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>")
        space:6

        C1["3"]
        C2["4"]
        C3["5"]
        C4["6"]
        C5["<span style="font-size:80%">3 4 5 6</span> 7"]
        C6["8"]
        C7["9"]
    end

    block:Middle
        columns 10

        TimeStart("<span style="color:Grey; font-size:80%;">TIME</span>")
        space:8
        TimeEnd(" ")

        space:10
    end

    block:Server
        columns 7

        ServerHeader(["<span style="color:white;"><b>Server</b> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>"])
        space:6

        S1["1"]
        S2["2"]
        S3["3"]
        S4["4"]
        S5["5"]
        S6["6"]
        S7["7"]
    end

    TimeStart --> TimeEnd
    C1 --"<span style="color:white; background-color:RoyalBlue;">&nbsp; Input (Frame 3) &nbsp;</span>"--> S3
    S3 --"<span style="color:white; background-color:SeaGreen;">&nbsp; Server State (Frame 3) &nbsp;</span>"--> C5

    style Client fill:RoyalBlue
    style ClientHeader stroke-opacity:0, fill-opacity:0

    style Middle fill-opacity:0, stroke-opacity:0
    style TimeStart fill-opacity:75%, stroke-opacity:75%
    style TimeEnd display:none

    style Server fill:SeaGreen
    style ServerHeader stroke-opacity:0, fill-opacity:0
```

_In the above diagram, the client is simulating 2 frames ahead of the server. It sends its inputs for frame 3 which arrive at the intended frame (3) on the server. The server sends the authoritative state for frame 3 and the client receives it on frame 7. The client discovers it mispredicted frame 3 so it resets to the server's frame 3 and resimulates frames 4, 5 and 6 before it simulates frame 7. Players may see a noticeable network artifact such as a sudden movement._

In summary, the **client**:

1. Receives the **authoritative state** from the server and compares it against its own **predicted state**.
2. If the client's prediction was incorrect:
  1. Client rolls back to the last known authoritative state received from the server.
  2. Client resimulates from the authoritative state to its predicted state, re-applying any local inputs.

## Implementation

### Network ownership and prediction

In the server authority model, you're able to keep the core gameplay objects server‑owned without incurring the input latency cost normally associated with server ownership. Things like cars, player characters, or other gameplay‑critical objects can remain server‑owned, even when interacting with other players.

By default, Roblox will automatically predict properties with [simulation access](#simulation-access) near the local player `Class.Player.Character|Character`, but if you want more fine‑grained control, you can explicitly force an instance's prediction on or off with `Class.RunService:SetPredictionMode()`.

Automatic prediction applies to whole physics assemblies, not individual instances. When the client predicts a part, it also predicts every part that's physically connected to it through welds, joints, or constraints, along with the parent `Class.Model` of those parts and any `Class.Humanoid` inside that model. For example:

- A sword model that's welded to a predicted character becomes part of the character's assembly, so it's predicted automatically.
- A model that's parented to the character but **not** physically connected to it is a separate assembly. It's only predicted if it's within the client's [simulation radius](/docs/en-us/projects/techniques.md#simulation-radius) or if you force prediction on with `Class.RunService:SetPredictionMode()`.

To check whether a specific instance is currently predicted, call `Class.RunService:GetPredictionStatus()` from the client.

### Simulation sync

In the server authority model, the client and the server must both run the core simulation, and the client's simulation needs to be able to [roll back and resimulate](#rollback-and-resimulation) when a [misprediction](#client-misprediction) occurs. To enable this, write your core logic inside functions bound through `Class.RunService:BindToSimulation()` in a `Class.ModuleScript` that's initialized on both the client and server.

![Server authority setup](../../assets/studio/explorer/ReplicatedStorage-Server-Authority.png)

During a resimulation, Roblox will re-run the functions bound to the simulation via `Class.RunService:BindToSimulation()|BindToSimulation()`. Processing player inputs, interacting with synchronized physics objects, and updating the core game state should live inside those bound functions.

Use `Global.RobloxGlobals.time()` for any time-based logic inside a bound simulation function, such as driving an animation speed or oscillating a value over time. When `Class.Workspace.AuthorityMode` is `Enum.AuthorityMode.Server`, `time()` is synchronized between the client and the server and uses fixed-step simulation time. During [resimulation](#rollback-and-resimulation), it rewinds to the authoritative frame and advances as the client replays frames, so it returns a consistent value each time a frame is simulated.

> **Warning:** Other time functions don't share this behavior. `Global.RobloxGlobals.tick()` and `Library.os.time()` read the local device clock, while `Library.os.clock()` measures elapsed time from an arbitrary local baseline. They aren't synchronized between the client and the server and don't roll back during resimulation, so avoid them for simulation-affecting logic.

#### Simulation

`Class.ModuleScript` named `Simulation` in `Class.ReplicatedStorage`:

```lua
local RunService = game:GetService("RunService")
local Players = game:GetService("Players")

local Simulation = {}

Simulation.Initialize = function()
	RunService:BindToSimulation(function(deltaTime)
		-- Read player inputs
		-- Update game state
	end)
end

return Simulation
```

#### ServerLoader

`Class.Script` named `ServerLoader` as child of the `Simulation` `Class.ModuleScript`:

```lua
local Simulation = require(script.Parent)

Simulation:Initialize()
```

#### ClientLoader

`Class.LocalScript` named `ClientLoader` as child of the `Simulation` `Class.ModuleScript`:

```lua
local Simulation = require(script.Parent)

Simulation:Initialize()
```

### State sync with attributes

Roblox automatically synchronizes all properties with [simulation access](#simulation-access) on predicted instances. For custom data, [attributes](/docs/en-us/studio/properties.md#instance-attributes) are the primary way to synchronize instances marked as predicted; on such instances, any mismatch in attribute values between the server's source of truth and the client's prediction will trigger a full [rollback and resimulation](#rollback-and-resimulation).

> **Success:** Use attributes to store game data that affects your core simulation, including player health, ammunition, inventory, or custom rules (see [limitations](#attribute-limits)).
> **Warning:** Only write to attributes on **predicted** instances from within functions bound through `Class.RunService:BindToSimulation()|BindToSimulation()` to ensure that Roblox can fully track relevant game states and resimulate properly.
#### Attribute limits

In order to be replicated, an attribute must meet all of the following criteria:

- It is among the first 64 attributes on its `Class.Instance`.
- Its name contains at most 50 characters.
- If a string type attribute, its value contains at most 50 characters.

#### Simulation access

Many properties and methods in the engine API reference include the **Simulation Access** label, for example `Class.BasePart.CFrame`. Properties with this label will be predicted by the server authority system. Additionally, only properties and methods with this label can be accessed inside functions bound with `Class.RunService:BindToSimulation()`.

### Create and remove instances

Inside functions bound through `Class.RunService:BindToSimulation()|BindToSimulation()`, you can create instances with `Datatype.Instance.new()`, `Class.Instance:Clone()`, or `Datatype.Instance.fromExisting()`. The client creates the instance immediately, and Roblox merges it with the server's authoritative copy when that copy arrives. For details, see [predictive instance creation](/docs/en-us/projects/techniques.md#predictive-instance-creation-instance-stitching).

Removing instances works differently. `Class.Instance:Destroy()` doesn't have [simulation access](#simulation-access), and you can't change the `Class.Instance.Parent|Parent` of an instance that's already in the `Class.DataModel`, so calling either inside a bound function causes an error. Instead, record the intent to remove an instance in an [attribute](#state-sync-with-attributes) inside the simulation, then remove the instance outside the simulation, such as in a `Class.RunService.PostSimulation|PostSimulation` connection on the server.

```lua
local RunService = game:GetService("RunService")

local character = script.Parent

RunService.PostSimulation:Connect(function()
	-- "SwordEquipped" is written by the simulation when the player unequips the sword
	local sword = character:FindFirstChild("Sword")
	if sword and not character:GetAttribute("SwordEquipped") then
		sword:Destroy()
	end
end)
```

> **Warning:**`Class.Tool|Tools` aren't fully supported in the server authority model yet. `Class.Humanoid:EquipTool()` and `Class.Humanoid:UnequipTools()` don't have [simulation access](#simulation-access), so they can't be called inside bound functions. To build an equippable item such as a sword, clone and weld a `Class.Model` to the character inside the simulation and track whether it's equipped with an attribute.
### Input actions

In a server-authoritative game, the primary way for a client to affect the game's state is through the [Input Action System](/docs/en-us/input/input-action-system.md). These inputs are sent to the server and are replayed during resimulation on the client. As a result, `Class.InputAction|InputActions` should be used for **all inputs that affect the core simulation** and they should be checked for sanity before they're processed.

> **Warning:** To reiterate, do not use traditional events like `Class.UserInputService.InputBegan` in the core simulation of a server-authoritative game.

Note that `Class.InputContext|InputContexts` must be a descendent of a `Class.Player` so that the engine knows who has ownership over the `Class.InputContext`. One approach is to add your `Class.InputContext|InputContexts` to a folder under `Class.ReplicatedStorage` and use a `Class.Script` under `Class.ServerScriptService` to clone the `Class.InputContext|InputContexts` per player:

```lua
local Players = game:GetService("Players")
local ReplicatedStorage = game:GetService("ReplicatedStorage")

local InputsFolder = ReplicatedStorage:WaitForChild("Inputs")

local function onPlayerAdded(player)
	local clone = InputsFolder:Clone()
	clone.Parent = player
end

Players.PlayerAdded:Connect(onPlayerAdded)

for _, player in Players:GetPlayers() do
	onPlayerAdded(player)
end
```

Using this pattern, you can read `Class.InputAction|InputActions` for all players in `Class.RunService:BindToSimulation()` on both client and server to receive the same data for a given frame and record the previous frame's input in an [attribute](/docs/en-us/studio/properties.md#instance-attributes), for example to trigger a character run when a `RunAction` input action is triggered.

### Remote events

[Remote events](/docs/en-us/scripting/events/remote.md) can still be used within the server authority model to facilitate discrete communication between client and server. For example, servers can use remote events to broadcast data about players scoring points or picking up objects, and clients can use remote events as an alternative API for sending inputs to the server, such as for button presses or tapping objects in the 3D world.

> **Warning:**`Class.RemoteEvent|RemoteEvents` might not be consistently ordered with property and attribute updates over the network. For example, if you change a property before firing a remote event on a client, the server might receive the property change after the remote event. To learn more, see [replication order](/docs/en-us/scripting/attributes.md#replication-order).
### Animations

Animations that affect gameplay, such as character movement or attack animations, should be controlled inside functions bound through `Class.RunService:BindToSimulation()|BindToSimulation()` in the same `Class.ModuleScript` that runs on both the client and server. Core `Class.Animator` and `Class.AnimationTrack` members such as `Class.Animator:LoadAnimation()|LoadAnimation()`, `Class.AnimationTrack:Play()|Play()`, `Class.AnimationTrack:Stop()|Stop()`, `Class.AnimationTrack:AdjustSpeed()|AdjustSpeed()`, and `Class.AnimationTrack.TimePosition|TimePosition` have [simulation access](#simulation-access).

Animation state is part of the predicted simulation. When a [rollback](#rollback-and-resimulation) occurs during an animation, the client rewinds the animation to the authoritative state and replays it along with the rest of the simulation, so client and server animations stay in sync. Because the client may replace animation tracks during a rollback, don't cache `Class.AnimationTrack` references across frames. Instead, look up the live track each frame with `Class.Animator:GetTrackByAnimationId()`. For a full example, see [writing animation code](/docs/en-us/projects/techniques.md#writing-animation-code).

### Sounds and effects

Client-side effects like sounds and particles must be written knowing that the client simulation is merely a prediction of the authoritative server state. `Class.RunService:BindToSimulation()|BindToSimulation()` limits what properties and methods can be called from within bound functions to help guide you in writing only to the synchronized simulation state. Displaying the results of this simulation, triggering effects and sounds, etc. should be done in a separate function connected to `Class.RunService.RenderStepped|RenderStepped` that reads the results of the simulation and triggers the desired effects.

Because the client might predict an event that never happens on the server, your rendering code should be able to undo or hide mispredicted effects. Further guidance around rendering a predicted simulation is covered in [playing sounds and visual effects](/docs/en-us/projects/techniques.md#playing-sounds-and-visual-effects).

## Example projects

In addition to this documentation, the following templates can help you get started:

_Racing_

_Soccer_

_Laser Tag_