As your Roblox game grows past a handful of scripts, duplicated logic becomes a maintenance problem. ModuleScripts are Roblox's tool for organizing and reusing code across multiple scripts. They run once, return a shared reference, and let you call the same function from any script that requires them.
Anatomy of a ModuleScript
Every ModuleScript starts with the same structure:
Code: Select all
local MyModule = {}
return MyModuleYou add functions to the table using the dot operator:
Code: Select all
local RewardManager = {}
function RewardManager.getCoinReward(difficulty)
local coins = 50
local multiplier = { easy = 0.5, normal = 1, hard = 2 }
return coins * multiplier[difficulty]
end
return RewardManagerCode: Select all
localRequiring Modules
To use a ModuleScript from another script, you call
Code: Select all
require()Code: Select all
local RewardManager = require(game.ServerScriptService.RewardManager)
local coins = RewardManager.getCoinReward("hard")
print(coins) -- 100Code: Select all
require()Where to Place ModuleScripts
ReplicatedStorage is the most common location because it is accessible from both the server and the client. ServerScriptService works for server-only modules. For shared configuration values that both sides need, put the ModuleScript in ReplicatedStorage and require it from both contexts.
Important: when you require a ModuleScript from both the server and a LocalScript, each side gets its own unique reference. The module runs independently in each environment. A module that touches DataStore on the server does not run on the client, and vice versa.
Common Patterns
Data sharing is the most basic use. Instead of scattering config values across every script, store them in a module:
Code: Select all
local GunConfig = {}
GunConfig.MagazineSize = 20
GunConfig.Damage = { Head = 50, Torso = 40, Body = 25 }
return GunConfigCode: Select all
local NetworkManager = {}
local remoteEvent = game.ReplicatedStorage:WaitForChild("RemoteEvent")
function NetworkManager.FireServer(id, ...)
remoteEvent:FireServer(id, ...)
end
return NetworkManagerCustom events through BindableEvents are another useful pattern. A module can expose an event and a setter function, and any script can connect to that event without needing a direct reference to the module's internals.
Circular Dependencies
One pitfall: if ModuleA requires ModuleB and ModuleB requires ModuleA, the require call hangs forever with no error message. This is easy to create when modules grow interdependent. The fix is to restructure: extract the shared logic into a third module that both can require, or use a deferred initialization pattern where one module accepts its dependency through an
Code: Select all
init()Summary
ModuleScripts are the backbone of any large Roblox codebase. They reduce duplication, give you a single place to fix bugs, and let you organize code by feature instead of by script type. Start with simple data modules, then move to encapsulation patterns as your game grows.
Sources
[1] Roblox Creator Docs: ModuleScript
[2] Roblox Creator Docs: Intro to Module Scripts
[3] Roblox Creator Docs: Script Locations