A hybrid ModuleLoader for Roblox (Luau) designed to handle client-side, server-side, and shared modules in a clean and scalable way.
This system automatically loads modules based on their execution context and injects shared data (modules, remotes, config, players, etc.) through a unified GetModules / Create pipeline.
ReplicatedStorage
└── Modules
├── ClientSide
├── ServerSide
└── Helpers
ServerStorage
└── Modules
├── Config
└── (Server-only modules)- Server-only modules
- Automatically loaded only on the server
- Ideal for game logic, systems, configs, services
- Client-only modules
- Loaded only on the client
- Server-side logic that needs to live in ReplicatedStorage
- Shared modules
- Available on both client and server
- Ideal for utilities, handlers, shared systems
The loader scans all valid folders depending on the execution context:
RunService:IsServer()→ loads Server + HelpersRunService:IsClient()→ loads Client + Helpers
Each module can expose either:
- a
GetModules(modules)function - or be a function itself
- or expose a
Create(data)method
The loader automatically:
- requires all modules
- caches them
- groups them by context
- injects dependencies
local Server = {}
local Remotes = {
Broadcast = game.ReplicatedStorage.Remotes.Broadcast,
Requests = game.ReplicatedStorage.Remotes.Requests,
}
local Players = game:GetService("Players")
function Server:GetModules(modules)
local configModule = modules.ConfigModule
if modules.ServerSide and type(modules.ServerSide.Create) == "function" then
modules.ServerSide:Create(modules)
end
for _, module in pairs(modules) do
if type(module.Create) == "function" then
module:Create({
modules = modules,
remotes = Remotes,
players = Players,
config = configModule,
})
end
end
end
return ServerClient-Side Entry Example
local Client = {}
local Remotes = {
Broadcast = game.ReplicatedStorage.Remotes.Broadcast,
Requests = game.ReplicatedStorage.Remotes.Requests,
BindableEvent = game.ReplicatedStorage.Remotes.BindableEvent,
}
function Client:GetModules(modules)
for _, module in pairs(modules) do
if type(module.Create) == "function" then
module:Create({
modules = modules,
remotes = Remotes,
})
end
end
end
return ClientGetting Modules from Client Side To retrieve and initialize a module from the client, use:
ModuleName:Create(data)The data table comes from GetModules(modules) and can contain:
other modules
RemoteEvents / RemoteFunctions
shared config
any custom injected data
You can freely extend what gets passed to Create.
Helpers Example (Shared Module) Modules inside Helpers can run on both client and server using:
RunService:IsServer()
RunService:IsClient()Example pattern:
Copy code
function Module:Create(data)
if RunService:IsServer() then
-- server logic
else
-- client logic
end
endThis makes Helpers ideal for:
minigame handlers
shared systems
state synchronization logic
Notes The loader automatically detects execution context
No manual requires needed across the project
Encourages modular, scalable architecture
Designed for large projects with shared logic
For a deeper explanation, see: ReplicatedStorage/Modules/ClientSide <-> ServerSide/README