Skip to content

Limits and security ​

Script limits ​

LimitValueWhat happens past it
Running without waiting1 secondThe script is stopped with an error. Put task.wait() in long loops
All a server's scripts, one step1 secondThreads still due wait for the next step; that step's remaining event handlers are skipped once
Memory, per script runtime64 MBThe script stops with an error; the game and its other scripts go on
Handlers on one event10,000connect is an error (usually a connect inside a loop)
A ClientScript or Module players get64 KB of textIt never reaches the players. Split it into Modules
A net message16 KB
A data value16 KB
data requests in flight64 per server
JSON100 levels deep, 16 MBAn error

World limits ​

LimitValue
Parts (Models and Folders count)10,000
A world going live16 MB
A part's size0.05 to 2,048 units a side
Positionswithin a million units of the middle
Models (MeshPart meshes)64 a world, 65,535 points each
Collision groups of the world's own13
Players per server1 to 100
Uploaded pictures64 a world, 1,024 px a side
Uploaded sounds32 a world, 20 MB and two minutes each, .wav
Achievements100 a game

What players can send ​

A player's app sends the server only what the game asks for, and the server holds it to:

  • 120 messages a second (net.send, net.call), 20 clicks and 20 tool actions. The rest are dropped.
  • Numbers must be real: NaN or infinity refuses the whole message.
  • A part from ServerService or StorageService, or one that is gone, arrives as nil.
  • Movement is the server's: it moves every character with its own walkSpeed and jumpPower, so a player can't speed or fly by changing their app.
  • Prompts, Clickables, gameplay bricks and building are checked on the server - reach, the part being on, the player alive.

Writing secure games ​

A player can run a modified app and send any arguments with any message name your scripts listen for. So:

  1. Never take a result from a player. Not an amount, a price, a damage, a target, a score. The client says what it wants to do; the server works out what happens.
  2. Check that they may do it now: alive, near enough, the cooldown passed, owns the item, can afford it.
  3. Keep secrets on the server. Every ClientScript - and every Module it can require - is sent to every player (without its comments). Codes, admin lists and server-only logic go in ServerService or StorageService.
  4. Validate types. A message's arguments can be anything: check typeof(x) == "string" before using x as a string.
lua
-- Bad: the client decides the price and the reward
net.on("buy", function(player, item, price)
    player.stats.Coins -= price
end)

-- Good: the server knows the price
local PRICES = {Sword = 50}
net.on("buy", function(player, item)
    if typeof(item) ~= "string" then return end
    local price = PRICES[item]
    if not price or player.stats.Coins < price then return end
    player.stats.Coins -= price
    shared.Items[item]:clone().parent = player.backpack
end)

Numbers that reach the engine are checked where they go in: a NaN position is an error your script can catch with pcall, and huge values are held within the world's limits. Health stops at a billion, speeds at 100,000 units a second.

The sandbox ​

Scripts run sandboxed: no files, no network, no other processes. HttpService's web requests are an error - a KHIM game doesn't reach the web. print from a ClientScript shows in the player's F3 panel; from a Script, in the server's console (the Workshop's Live > Console for a live game). Script errors never reach the game's chat.