
Modules: Organizing and Sharing Verse Code
Modules: Organizing and Sharing Verse Code
A growing UEFN project is dozens — sometimes hundreds — of .verse files. Without a way to group them and control what's visible across them, every name would collide and every file would see everything. Verse's answer is the module: a named container for related code. Modules are how you split a project into systems (SaveSystem, NpcSystem, UISystem), how you pull in Fortnite's APIs with using, and how you decide what's <public> (shared) versus <internal> (private to the module). This lesson ties the whole track together: the access specifiers you'll set here use the same angle-bracket syntax as the effect labels from earlier lessons.
Two kinds of module you already use
<!-- section-art:two-kinds-of-module-you-already-use -->

Dual Module Paths
Every using line at the top of a Verse file names a module. You've been using modules since your first device:
using { /Fortnite.com/Devices } # Fortnite's device APIs
using { /Verse.org/Simulation } # agent, @editable, core sim types
using { /UnrealEngine.com/Temporary/Diagnostics } # Print and logging
Those slash-paths are Epic's modules: /Fortnite.com/..., /Verse.org/..., /UnrealEngine.com/.... A using opens a module so you can write its names unqualified — button_device instead of the full path. These three are the most common in real code (/Verse.org/Simulation and /Fortnite.com/Devices appear in the vast majority of device files).
The second kind is your own modules — the systems you build. In our project, a file opens sibling systems the same way:
# Real corpus using-lines for project modules.
using { Verse.Scripts.Utils }
using { SaveSystem }
using { ConfigSystem }
So using is a single idea applied to both Epic's library and your own code: bring this module's public names into scope.
How a module is structured
A module is declared with := module. There are two forms.
Folder modules — a folder in your Verse project is a module, named after the folder. Our project's permissions.verse declares the whole tree this way. This is real, lightly trimmed corpus code:
# Real shape from permissions.verse — folders declared as modules.
Scripts<public> := module:
SaveSystem<public> := module:
Core<public> := module:
NpcSystem<public> := module:
UISystem<public> := module:
Utils<public> := module:
Unused<internal> := module: # visible only inside Scripts
Indentation shows nesting: Core lives inside SaveSystem, which lives inside Scripts. The full path to Core is Scripts.SaveSystem.Core.
Inline modules — you can also declare a small module right in a file with braces:
# An inline module grouping math helpers in one named box.
MathHelpers<public> := module {}
Either way, the module is a namespace: a box that holds names (functions, classes, constants) and keeps them from colliding with names in other boxes.
Accessing module contents: using vs. qualified names
Once a module exists, there are two ways to reach what's inside.
1. Open it with using — then write its names bare:
using { Verse.Scripts.Utils } # open the Utils module
# now Format (a public function inside Utils) is available unqualified
Label := Format("Score", Points)
2. Qualify the name — write the path inline without a using. The digest does this constantly to disambiguate:
# Fully-qualified call — no using needed, path written inline.
Color := (/Verse.org/Colors:)MakeColorFromHex("FF8800")
Use using for modules you touch a lot (cleaner), and qualified names when you reference something once or need to disambiguate two same-named things from different modules.
Scoping: <public> vs. <internal>
This is the part that trips people up, and it's the reason modules are more than just folders. Each name in a module carries an access specifier — the same angle-bracket syntax as effect labels — that controls who can see it:
<public>— visible to code outside the module. This is the module's published surface.<internal>— visible only within the same module (and its submodules). A private helper.<protected>/<private>— finer-grained, mainly for class members (private = only this class; protected = this class and subclasses).
# A module that exposes one function and hides its helper.
ScoreUtils<public> := module:
# Published — other systems may call this.
FormatScore<public>(Points : int) : string =
"Score: {PadNumber(Points)}"
# Internal — only ScoreUtils itself can use this. Outsiders can't see it.
PadNumber<internal>(N : int) : string =
if (N < 10) then "00{N}" else "{N}"
From another system, ScoreUtils.FormatScore(...) works after using { ScoreUtils }, but PadNumber is invisible — it's an implementation detail. This is the same instinct as keeping classes focused: expose the smallest surface that does the job, and hide the rest. Our permissions.verse uses exactly this — most systems are <public> so games can use them, while Unused<internal> stays hidden.
The default matters: if you don't write an access specifier, a member is more restricted than <public> — so to share something across modules you must explicitly mark it <public>. Forgetting that is the #1 module mistake (covered below).
A worked example: a small shared utility module
Putting it together — a focused Utils module with a public helper, opened from a device:
# --- file: Games/MyGame/banner_device.verse ---
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
banner_device := class(creative_device):
OnBegin<override>()<suspends> : void =
Line := "===================="
Print(Line)```
One module owns the helper; the device opens it with `using` and calls it unqualified. If `Repeat` weren't marked `<public>`, the device couldn't see it — the compiler would say the name is unknown.
## Naming and layout conventions
Our project organizes each system as a folder-module with a consistent file pattern (from the project conventions): `_module.verse` (shared functions), `_data.verse` (data structures), `_config.verse` (configuration), `_controller.verse` (the `creative_device`). A system is **self-contained**: it exposes a public surface and keeps its internals private. Following a predictable layout means anyone — human or AI helper — can find the right file by name.
## The pitfalls — what trips people up
<!-- section-art:the-pitfalls-what-trips-people-up -->

*Module Pitfalls*
**1. Forgetting `<public>`.** A function or class with no access specifier is **not** automatically visible across modules. You `using` the module, the name still isn't found, and it's baffling — until you realize you never marked it `<public>`. To share, you must say so.
**2. Confusing `using` with importing the file.** `using` opens a *module* (a namespace), not a file. The folder structure defines the module path; `using { Verse.Scripts.Utils }` opens the `Utils` folder-module, regardless of how many files are in it.
**3. Wrong module path.** `using { Utils }` vs `using { Verse.Scripts.Utils }` — the path must match the actual nesting. If `Utils` is nested under `Scripts`, you generally need the qualified path (or a `using` of the parent). A path that doesn't match the folder tree won't resolve.
**4. Over-exposing internals.** Marking every helper `<public>` turns your module into a tangle that other systems start depending on, so you can't change it later. Publish the minimum; keep helpers `<internal>`. This is single-responsibility at the module level.
**5. Circular `using`.** Two modules that each `using` the other create a dependency cycle. Keep dependencies flowing one direction (e.g. games depend on systems, not the reverse), as the project's layered structure does.
**6. Treating Epic paths and project paths as different mechanisms.** They're the same: `/Fortnite.com/Devices` and `Verse.Scripts.Utils` are both module paths opened by `using`. Epic's just start with a slash (absolute, from the engine root).
## Recap
- A **module** is a named container (namespace) for related code; `:= module` declares one, as a **folder module** or an **inline** `module {}`.
- **`using`** opens a module so you can write its names unqualified — the same idea for Epic's APIs (`/Fortnite.com/Devices`) and your own systems (`Verse.Scripts.Utils`). You can also write **qualified names** inline.
- **`<public>`** publishes a name across modules; **`<internal>`** keeps it private to the module. No specifier means *not* public — you must explicitly mark what you share.
- Expose the **smallest public surface** and hide the rest; lay systems out predictably (`_module`/`_data`/`_config`/`_controller`).
- Watch for the classics: forgetting `<public>`, wrong module paths, over-exposing internals, and circular dependencies.
## References
- [Verse Language Reference (Epic)](https://dev.epicgames.com/documentation/en-us/uefn/verse-language-reference)
- [Modules and paths in Verse (Epic)](https://dev.epicgames.com/documentation/en-us/uefn/modules-and-paths-in-verse)
- [Access specifiers in Verse (Epic)](https://dev.epicgames.com/documentation/en-us/uefn/access-specifiers-in-verse)
- Grounded in the Verse Cortex knowledge base: real corpus `permissions.verse` (folder-module tree with `<public>`/`<internal>`), corpus `using` lines (`/Fortnite.com/Devices`, `/Verse.org/Simulation`, `Verse.Scripts.Utils`, `SaveSystem`), the digest's qualified-name calls, and project conventions (CityOfBrains module layout: `_module`/`_data`/`_config`/`_controller`).
Get the complete code — free
You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.
Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.
Check your understanding
Test yourself with an interactive quiz and track your progress + earn XP — free for members.
Turn this into a guided course
Add Verse modules — folder vs inline modules, namespaces and paths, the using statement, qualified names, and access specifiers (<public> / <internal> / scoping) to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.
Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.