Roblox games are built on a tree of Instances rooted atDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/brockmartin/roblox-game-skill/llms.txt
Use this file to discover all available pages before exploring further.
game. Every object — parts, scripts, UI elements, sounds — lives somewhere in that hierarchy, and its location determines its behavior: a Script in ServerScriptService runs exclusively on the server, while the same Script placed in StarterPlayerScripts would not run at all. Understanding which container to use, how client and server communicate, and how to organize ModuleScripts is the foundation of every maintainable Roblox codebase. This reference covers the canonical patterns from small game-jam projects all the way to large framework-based games.
Client vs. Server Execution
| Aspect | Server | Client |
|---|---|---|
| Runs on | Roblox datacenter (one instance per game server) | Each player’s device |
| Script types | Script (Luau), ModuleScript (when required by a server script) | LocalScript, ModuleScript (when required by a local script) |
| Trust level | Authoritative — owns game state, data stores, physics arbitration | Untrusted — can be exploited; never trust client input blindly |
| Access | Can see everything in the data model | Cannot see ServerScriptService or ServerStorage |
Service Hierarchy
Roblox replicates parts of the data model from server to clients automatically. Knowing what lives where — and who can see it — is critical for both security and performance.Replication Summary
| Service | Who Sees It | Replicated? | Use For |
|---|---|---|---|
ServerScriptService | Server only | ❌ Never | Server Scripts, server-only modules |
ServerStorage | Server only | ❌ Never | Server assets, templates, secret modules |
ReplicatedStorage | Server + all clients | ✅ Always | Remotes, shared modules, shared assets |
ReplicatedFirst | Server + all clients | ✅ First | Loading screens, early client init |
StarterGui | Server (template) | ✅ Per-player | UI ScreenGuis cloned into PlayerGui |
StarterPlayerScripts | Server (template) | ✅ Per-player | LocalScripts cloned into PlayerScripts |
StarterCharacterScripts | Server (template) | ✅ Per-spawn | Scripts cloned into character on spawn |
StarterPack | Server (template) | ✅ Per-spawn | Default tools cloned into Backpack |
Workspace | Server + all clients | ✅ Always | The 3D world — parts, terrain, models |
ServerScriptService
ContainsScript instances that run exclusively on the server. Clients cannot see or access anything inside.
Use for: Core game logic (round systems, match management), DataStore calls, server-side validation, anti-cheat enforcement, NPC/AI controllers, and server-only modules.
ServerStorage
A server-only container for assets and modules that clients should never download. Use for: Map models cloned into Workspace on demand, enemy/NPC templates, server-only utility libraries, data schemas.ReplicatedStorage
Shared container visible to both server and client. Content is replicated to every client on join. Use for:RemoteEvent and RemoteFunction instances (the communication bridge), shared ModuleScript modules (utilities, constants, types), assets both sides reference.
StarterGui
UI template container. On each player spawn, contents are cloned into that player’sPlayerGui.
Set
ScreenGui.ResetOnSpawn = false for persistent UI that should not re-clone on character respawn.StarterPlayerScripts and StarterCharacterScripts
LocalScript instances in StarterPlayerScripts are cloned into each player’s PlayerScripts folder once on join and persist across respawns. Scripts in StarterCharacterScripts are cloned into the player’s Character model each time the character spawns — they are destroyed on death.
Script Types
Script (Server)
Runs on the server. Valid in
ServerScriptService. Full access to server APIs. Use .server.lua suffix in Rojo projects.LocalScript (Client)
Runs on the player’s device. Valid in
StarterPlayerScripts, StarterGui, StarterPack, and character. Use .client.lua suffix.ModuleScript (Both)
Runs on whichever side
require()s it. Returns exactly one value. Location determines who can access it — ReplicatedStorage for shared, ServerStorage for server-only.Script Type Reference
| Type | Runs On | Valid Containers | File Convention |
|---|---|---|---|
Script | Server | ServerScriptService, Workspace (avoid) | *.server.lua |
LocalScript | Client | StarterPlayerScripts, StarterCharacterScripts, StarterGui, StarterPack, PlayerGui, Character | *.client.lua |
ModuleScript | Caller’s side | Anywhere — location controls access | *.lua |
Client-Server Communication
Communication Type Reference
| Type | Direction | Blocking? | Reliable? | Use Case |
|---|---|---|---|---|
RemoteEvent | Client ↔ Server | No | Yes | Actions, notifications, state changes |
RemoteFunction | Client → Server only (safe) | Yes (yields) | Yes | Data requests, queries |
BindableEvent | Same side | No | N/A (local) | Decoupled same-side messaging |
BindableFunction | Same side | Yes (yields) | N/A (local) | Same-side request/response |
UnreliableRemoteEvent | Client ↔ Server | No | No | High-frequency cosmetic data |
RemoteEvent (Async, One-Way)
Use for fire-and-forget messages where the sender does not need a response.- Server to Client
- Client to Server
RemoteFunction (Sync, Request-Response)
Use when the client needs a return value from the server.BindableEvent (Same-Side Communication)
Use for decoupled communication between scripts on the same side. Does not cross the network boundary.UnreliableRemoteEvent (High-Frequency, Loss-Tolerant)
Use for data sent very frequently where occasional packet loss is acceptable. Do not use for damage, purchases, or any authoritative state change.Server-Side Validation Pattern
EveryOnServerEvent and OnServerInvoke handler must validate its inputs before acting.
ModuleScript Organization
Basic Module Pattern
Every ModuleScript returns a single table. Functions and state are fields on that table.The require() Pattern
A module runs once. Subsequent
require() calls return the cached result. If a server Script and a LocalScript both require the same module in ReplicatedStorage, they each get their own copy running in their respective context.Avoiding Circular Dependencies
Circular dependencies occur when Module A requires Module B and Module B requires Module A. This causes one module to receive an incomplete (empty table) reference.- Problem
- Fix: Deferred Init Pattern
- Fix: Dependency Inversion
- Fix: BindableEvent Decoupling
OOP Module Pattern
Centralize Remote Definitions
Create all RemoteEvents and RemoteFunctions in one place rather than scatteringInstance.new("RemoteEvent") across scripts.
Framework Patterns
No Framework (Manual)
Best for game jams, prototypes, and small games with under ~10 scripts. Minimal boilerplate; full control.Single Script Architecture (SSA)
One server Script and one client LocalScript. Each requires a loader module that initializes all other modules in order.Knit Framework
Knit structures server code into Services and client code into Controllers with automatic networking.- Server Service
- Client Controller
- Bootstrapper
Framework Comparison
| Aspect | No Framework | Single Script Architecture | Knit |
|---|---|---|---|
| Complexity | Low | Medium | Medium-High |
| Boilerplate | Minimal | Low | Moderate |
| Networking | Manual RemoteEvent setup | Manual | Automatic (Services expose Client API) |
| Learning curve | Just Roblox APIs | Small pattern | Framework-specific concepts |
| Scalability | Degrades without discipline | Good with init/start pattern | Good, enforced structure |
| Dependency management | Manual require chains | Centralized loader | Built-in service discovery |
| Best for | Jams, small projects | Medium projects, teams wanting control | Larger projects, teams wanting convention |
Folder Organization
- Small Game
- Medium Game
- Large Game (Rojo)
For game jams, prototypes, or games with fewer than ~10 scripts.
Best Practices
Server owns all state
The server is the single source of truth. Clients render and predict; the server validates and authorizes. The client sends intent (“I attacked this target”), not outcome (“deal 500 damage”).
Single responsibility per module
One module = one job. If a module handles inventory AND crafting AND trading, split it into
InventoryModule, CraftingModule, and TradingModule.Use ModuleScripts everywhere
Keep Scripts and LocalScripts as thin bootstrappers that require and initialize ModuleScripts. Never put core game logic directly in a Script.
Validate all client input
Every
OnServerEvent and OnServerInvoke must check type, range, existence, ownership, and rate. Treat all client data as adversarial.Centralize Remote definitions
Create all RemoteEvents and RemoteFunctions in a single setup script. Scatter
Instance.new("RemoteEvent") calls and you will lose track of your API surface.Keep server logic out of ReplicatedStorage
Only put genuinely shared code (types, constants, utilities) in
ReplicatedStorage. Exploiters can read everything there. Validation logic, rate limit thresholds, and damage formulas belong in ServerScriptService or ServerStorage.Architecture Anti-Patterns
God Scripts
God Scripts
Problem: One massive script (500+ lines) that handles spawning, combat, data, UI, and everything else. Impossible to debug, modify, or collaborate on.Fix: Break into ModuleScripts with clear responsibilities. The main script becomes a thin bootstrapper that requires and initializes them.
Circular Requires
Circular Requires
Problem: Module A requires Module B, which requires Module A. One of them receives an incomplete (empty table) reference, causing subtle nil-method errors.Fix: Use the deferred
init() pattern (pass a modules table after all requires complete), extract shared logic into a third module, or use BindableEvent-based decoupling.Server Logic in ReplicatedStorage
Server Logic in ReplicatedStorage
Problem: Placing server-only game logic modules in
ReplicatedStorage. Exploiters can read the source code and craft targeted exploits against your validation logic.Fix: Only put genuinely shared code in ReplicatedStorage. Keep validation rules, anti-cheat logic, and server formulas in ServerScriptService or ServerStorage.Scripts in Workspace
Scripts in Workspace
Problem: Placing Scripts directly as children of Workspace or inside Workspace models. They are visible to exploiters, hard to find, and create organizational chaos.Fix: Put all server scripts in
ServerScriptService. Reference models via path or CollectionService tags from within the service.Trusting Client Data
Trusting Client Data
Problem: Server blindly applies whatever the client sends — damage values, item quantities, positions.Fix: The client sends intent only. The server independently validates and calculates outcomes.
Polling Instead of Events
Polling Instead of Events
Problem:
while true do task.wait(1) loops to check if something changed, instead of connecting to events.Overusing RemoteFunctions
Overusing RemoteFunctions
Problem: Using
RemoteFunction for every interaction, including fire-and-forget actions. Each InvokeServer yields the client thread until the server responds, adding unnecessary latency.Fix: Use RemoteEvent for actions that do not need a return value. Reserve RemoteFunction for genuine data queries.Not Using the task Library
Not Using the task Library
Problem: Using deprecated
wait(), spawn(), and delay() which throttle, have imprecise timing, and swallow errors.