Introducing Require-by-String

Hello, everyone!

We are excited to announce a new Luau feature available in the Roblox engine: require by string! With this feature, you’ll be able to use string paths to require modules instead of navigating with Instances, making your code compatible with Luau code written for other runtimes and easier to read and write.

Details

String Path Resolution

Require-by-string allows you to require modules using relative paths.

  • The / symbol is used as a separator in paths.
  • Relative paths must start with ./ or ../.

For example, these two require calls are now equivalent.

local Module = require(script.Parent.Parent.Folder.ModuleScript)
local SameModule = require("../Folder/ModuleScript")

Init Support

Important: Some external tools such as Rojo have different semantics for files called init.luau. See our external tools section in the FAQ for more information.

Additionally, you can now require Instances containing a ModuleScript named Init or init. This aligns with the behavior we support for folders in external Luau code, where the folder’s init.luau script is used as the entry point. With this change, you can organize your code into a folder and require the folder itself, simplifying your project structure!

Autocomplete

To aid with development, autocomplete suggestions will pop up in Script Editor for each component as you type out paths in a require expression.

autocomplete

Type Checking

With strict mode enabled, you’ll also receive a type error for any path that cannot be resolved to a ModuleScript.

typechecking

Conclusion

This new feature, along with the early preview for Studio Script Sync, will make it easier for you to work with Luau written outside of Roblox. We’re excited for you to try out require-by-string, and we welcome your feedback. Please share your thoughts and experiences in this thread!

FAQs

Does require-by-string wait for ModuleScripts to replicate?

No, but waiting for game.Loaded to be fired using game.Loaded:Wait() will be sufficient when your scripts are not in Workspace. Otherwise, you can use Instance:WaitForChild() for manual synchronization.

Are absolute paths supported?

No. We intend to remain aligned with open-source Luau, which does not support requiring absolute paths. However, we are already working on solutions to make it easier to access common libraries regardless of where your scripts are in the experience or on the file system.

Are aliased paths supported?

Not yet, but we’re working on it! Support for aliases in require paths is an important step toward full cross-platform compatibility.

How does this work with external tools?

We decided to keep the current behavior for init files to ensure consistency with how Luau works outside of Roblox. While this decision may not fully address every use case, it helps avoid breaking existing projects and is the first step towards a unified Luau ecosystem.

For most external tools, you’ll be able to use require-by-string without issue. However, some tools have different semantics for init files, which may lead to compatibility issues.

In particular, Rojo treats init files as if they are the same as the directory they are in, converting them to ModuleScript Instances with children when importing them into Roblox. Visit Rojo: Sync Details to learn more. You’ll still be able to use require-by-string with Rojo, but you should be aware of this potential issue when importing projects.

To address this, we’re planning to introduce project-relative requires which will provide a consistent way to reference files in Roblox, on the file system, and when using external tools such as Rojo. We’ll share more details about that in the future. However, for now this is just the first step to enabling consistency between Luau runtimes.

Documentation

For additional information about require, please visit our documentation .

171 Likes

This topic was automatically opened after 10 minutes.

For a script to require a child of itself, you’ll have to do require("./{script}/child") where {script} is the name of the current script. Great stuff.

24 Likes

Before anyone asks: no, Rojo won’t be getting a toggle for this. At least for now. We made our position very clear during the extensive OSS discussion on this, and Roblox went down this path anyway. It won’t matter unless you intend to write cross-runtime code. But for those of you that do want to, blame Roblox. Don’t blame Rojo.

It’s impossible to overstate how disappointing I find it that there was no changes in behavior made from the initial OSS release of this feature to its public announcement, despite the feedback given. It feels borderline disrespectful.

What are projects, exactly? I’ve never gotten an answer from anyone on this, despite it being pushed as a priority. Evidently more so than aliasing, which is what most people will need to replace module loaders with require-by-string.

26 Likes

What about if you want to require a module script that is parented directly underneath the script?

4 Likes

This seems interesting? does this mean we wont have to type too many stuff like “game.replicatedstorage.modules.clientmodules.modulename” ? and instead type the module name

4 Likes

can’t believe this is real ive been waiting for this day my entire life :money_mouth_face:

4 Likes

It will allow for better package management :money_mouth_face:

2 Likes

This feels pretty half-baked…

Why is the dot amount capped at 2, and why is there no way to require a child module?

Just doesn’t feel very useful at the moment.

8 Likes

this is just how globs work, and it won’t change
in “real” filesystems there aren’t things like children

3 Likes

Okay just so you and everyone reading this is aware those aren’t globs. Like, I get what you’re saying but they’re closer to being URIs than globs.

The dots have special meaning. . is sibling, .. is parent. They’re limited because they’re special prefixes with meaning; more doesn’t mean anything.

5 Likes

Thats good to know.
I always thought that a single dot would be representing something like script.Parent, and 2 dots would be script.Parent.Parent and so on.

1 Like

Can I see the discussion post if available? I want to learn why they didn’t initially release this with cross-runtime support.

1 Like

Don’t mind me, but I am wondering why this functionality is being added? Why can’t we just use indexes by “.”?

1 Like

it introduces more compat between vanilla luau and roblox luau, and it’s also just preferred

2 Likes

As described in the announcement itself and in the RFCs on the subject, the long-term goal is to standardize the behavior of require in Luau to function the same across platforms. Luau is embedded in Roblox, but it’s also available as a standalone programming language, and is increasingly being embedded in other game engines. By defining a standard for how require works, we’re working towards a future where Luau code can be written in a runtime-agnostic way and be used in any of those environments. Essentially, this is part of a larger effort to make Luau itself a more consistent programming language in the interest of growing a healthy open source ecosystem around the language.

28 Likes

Interesting to see how Luau is being utilizing into different game-engines!

1 Like

I’m curious what the main issue is - scripts inside of scripts is a weird thing that doesn’t exist in normal file systems, and is a bit of a Robloxism.

What were the alternatives you guys suggested that were not favoured?

3 Likes

Im kinda confused… WHAT is a package?? isnt that like a modulescript that can be required from the web?

1 Like

a package is a piece of software designed to be distributed to many people

2 Likes