Getting Started
Modules is designed to be simple and straightforward.
1. Install Modules
After inserting Modules into your game, move the root "Modules" ModuleScript to ReplicatedStorage.
game
└ ReplicatedStorage
└ Modules
Anywhere in ReplicatedStorage will work, but it's recommended to be a direct child.
2. Create Your Namespace
To make a namespace, create a Folder in ServerScriptService and/or ReplicatedStorage. The Name of this folder should be distinct like any other object in the hierarchy, and ideally shouldn't contain symbols.
game
├ ReplicatedStorage
│ └ MyGame ← Create this Folder (for client stuff)...
└ ServerScriptService
└ MyGame ← ...and/or this folder (for server stuff)
It's recommended you use Pascal case for the name of your namespace. Examples: MyLibrary
, SomeOtherLibrary
, etc
3. Add ModuleScripts, and Everything Else
Add whatever ModuleScripts to your namespace folder you like. As with the namespace folder, you should follow a consistent naming scheme for your modules. Avoid non-alphanumeric characters. If a module needs assets, you can include those within it or somewhere else in your namespace folder.
Consider the following heirarchy, where the contents of Tools
are ModuleScripts:
game
├ ReplicatedStorage
│ ├ Modules
│ └ MyGame [Folder]
│ └ Tools [Folder]
│ ├ Sword
│ ├ Slingshot
│ └ Rocket Launcher
└ ServerScriptService
└ MyGame [Folder]
└ ServerManager
4. Require Your ModuleScripts
A string passed to require
should first specify a namespace, followed by a colon, then the module. If the Module is within other objects, separate their names with a period. Using the heirarchy above, from (3):
-- Some script in your game:
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Modules"))
local ServerManager = require("MyGame:ServerManager")
local Sword = require("MyGame:Tools.Sword")
local Slingshot = require("MyGame:Tools.Slingshot")
Modules uses the following process to locate the module:
- If no namespace was specified, assume the Modules ModuleScript is the namespace.
- Check for client module first: look for the namespace in ReplicatedStorage, if found, check it for the module.
- Check for server modules second: look for the namespace in ServerScriptService, if found, check it for the module. If either the namespace or module is missing, raise a "module not found" error.
If both the client and server require a shared library, but that shared library has a dependency only relevant to either the client or server, you can use require.server
or require.client
to skip the require and return nil if the code isn't running on that network peer:
-- Some ModuleScript that is required on both client and server
local require = require(game:GetService("ReplicatedStorage"):WaitForChild("Modules"))
-- Client won't be able to access this
local ServerManager = require.server("MyGame:ServerManager")
local MySharedLibrary = {}
-- Perhaps in MySharedLibrary there's a function which is
-- only called by the server, and that function might use ServerManager,
-- but we still want to enable the client to require this module for the other bits.
return MySharedLibrary
This is useful in a variety of cases. Most notably, if constants in a shared class module are needed by both the client and server, constructing the class might only be possible on the server. This could due to certain server dependencies, but using require.server
, the client can skip over those dependencies since it wouldn't be constructing the object and using those dependencies.
5. Use a "Replicated" Folder (Optional)
In some cases, like using Roblox Packages, it's desirable to unify all of a namespace's code (both server and client code) into one root object. You can replicate only part of a namespace folder in ServerScriptService using a "Replicated" Folder:
For namespace Folders in ServerScriptService, you may add a Folder named "Replicated". Such a folder is automatically replicated to clients: the folder is moved to ReplicatedStorage and renamed to the same as the namespace. Therefore, any ModuleScripts inside the Replicated folder can be required as if the Module were placed in ReplicatedStorage in the first place.
Consider the following game structure, which uses both ServerScriptService and ReplicatedStorage namespace folders. To unify the codebase into one object, we can move the client folder into the server folder and rename it "Replicated".
game
├ ReplicatedStorage
│ ├ Modules
│ └ MyNamespace ← Rename this "Replicated"...
│ └ SomeSharedModule
└ ServerScriptService
└ MyNamespace ← ...and move it into here.
└ JustAServerModule
After moving the ReplicatedStorage namespace folder to the ServerScriptService folder, and renaming it to "Replicated", the structure should now look like this:
game
├ ReplicatedStorage
│ └ Modules
└ ServerScriptService
└ MyNamespace
├ JustAServerModule
└ Replicated ← When Modules is loaded, this is moved to:
└ SomeSharedModule ReplicatedStorage.MyNamespace.SomeSharedModule
(which is what we had before, but now there's
a single root object for all of MyNamespace!)
6. Check out the Goodies
Modules comes with a few really useful classes you should never leave home without. See Overview#Structure for a list, or check out a few of these: Event, Maid, StateMachine.