ModuleScripts - An Introduction

Module Scripts are a powerful tool centered around a singular idea: allow code to be accessed from other scripts. If used properly, they can save hours of time and lines of code. Many modern games are built with almost 100% module scripts. If you know how to use module scripts, you can find yourself writing cleaner code that is easier to manage as the scale of your game increases.

Prefer video formats? Watch this!

How to create a Module Script
To create a module script, select the location you want to place it in, click the plus or insert object, and simply select module script.

Note: Module scripts adhere to the client/server boundary rules. A module script created in ServerScriptService will NOT be available on the client
Capture

Once your module script is created, you should see this:

local module = {}

return module

This may look different than the print("Hello World!") you are used to seeing upon creating a script. This is because module scripts can only function so long as a fundamental principle is followed: they return something.

Whether it be a table, a boolean, or a singular function, whatever the module returns can be accessed by other scripts.

99% of the time you use a module script, the goal is for it to return a table. This table can store data and functions, just as they would in a normal script. Anything put in the module table is returned, and thus accessible in whatever script retrieves this module.

The proper way a module is typically set up is like this:

  • Variables:
module.textToPrint = "Hello world!"
  • Functions:
function module:Print()
     print("Hello world!")
end

Both of these add the data to the table, meaning they are returned. Variables and functions within a module function exactly the same as they would in a normal script, but they must be indexed with the table’s name. There are some more facets to this with the introduction of the self keyword, but that’s for another time.

How to implement a Module Script
Implementing a module script is very simple. It is the same as referencing an object, but with a method wrapped around it.

What is the difference between these two lines of code?

local module = game.ServerScriptService.ModuleScript
local moduleScript = require(game.ServerScriptService.ModuleScript)

The first line is a reference to the actual module script object. This allows you to index common properties such as the name, parent, and more. This will NOT allow you to access the contents of the script. In order to do that, you must do as the second line did, using the require method. This will take a module and retrieve the value that is returned by it. That is why it is important that anything you want accessible by another script is added to the module’s table and returned. You cannot put code under the return statement in your module.

Once you have required the module, you can fire functions and access variables with ease:

moduleScript:Print()
print(moduleScript.textToPrint)

As you can see, modules can allow you to stick to a key programming principle: Don’t repeat yourself.
Any function you need to use multiple times, even with different inputs, can be placed in a module with parameters.

I hope you guys found this article useful, let me know if you have questions or if there are any issues/inconsistencies within this article. Thank you!

11 Likes

Nice start. You should make a part 2 to this that goes over metatables.

1 Like

I definitely will. I’m also planning out a very meticulous deep dive into using modules w/ OOP. Working on writing it with a focus on preventing OVERuse of it, since a lot of devs use oop wayyy too much.

1 Like

maybe also cover export
since it is for module scripts

Pretty good tutorial! Very brief and on point.

Quick corrections:

  • In the video, it states that you need to return a table from a module script. This isn’t the case, as you can return any value that’s not nil.

  • You don’t need to use : to define a function in the module (unless you want access to self, which is useful in OOP). It’s better practice to use . for non self accessing functions. But, it’s totally up to preference.


To add to the tutorial, think about module scripts as extensions of the script requiring it. A module is more or less a storage unit for different things that you want to access (or to simply organize code).

4 Likes

I’m aware of those corrections, I just wanted to keep it kind of basic. I use modules very often for readonly tables and singletons, but I didn’t want to overcomplicate it for other users. And I use : as a preference, but I get where you’re coming from. I may edit this eventually to talk more about self and its usage. Thanks for the feedback :slight_smile:

2 Likes

Amazing!! Really useful and is someonthing that I will deffinatly come back to in future!

Hello, are the functions in module scripts the same for the functions in normal scripts or are they different, also I’m having trouble understanding about “tables in module scripts” could you provide a link or explanation?

If I have understood your question properly then yes functions defined in a script or a module script are the same.
Here is a short definition of Module Script -
A ModuleScript is a type of Lua source container that runs once and must return exactly one value.

After reading that you can assume why module scripts are always used to return tables and that is because they can return Exactly one value , attempting to return a plural will result in this error :
Module code did not return exactly one value

Thus when using module script everything is put into tables and then the table is returned and you can access those elements using “.” ( dot operator ) or “:” Colon operator and they are a little different but unless you work with the keyword “self” you won’t need to worry about “:” or “.” , any of these would serve your purpose.

Coming to examples -

-- Module Script 
local module = {} 
function module.printlua() -- function made to print something and stored in the "module" table.  
    print("lua") -- prints lua 
end
-- Server script 
local module = require(script.modulescript) -- requiring the module script for use // returns the table 
module.printlua() --> "lua"

As you see this organises our code and if you want to use this function somewhere else you don’t need to repeat yourself and can just require the module and get the job done.

If you did not get something feel free to ask.

Ive seen people use module scripts on local scripts, I feel like that would be exploitable, are there limits to local scripts launching module script events?