backupRoswaal has moved to roswaal.app. These pages are a backup copy.Go to roswaal.app

Compiling and nodemaps for Roblox✎

How a graph becomes a file, and a file becomes an instance in Studio.

Verified

This page is about graphs whose Target is Roblox. The bar along the top of the canvas says which, and a new graph takes the project's. For Lune, the answer is a different one and it is on Compiling and nodemaps for Lune.

A graph is a .nodescript under .roswaal/scripts. Compiling it writes a .luau file to the same place under src, and Rojo syncs that into Studio. Roswaal never talks to Studio itself.

Folders carry across: .roswaal/scripts/ReplicatedStorage/Shared/Greeter.nodescript writes src/ReplicatedStorage/Shared/Greeter.luau. Both directories are project settings.

Nodemap basics

A .nodemap says where your files land in the DataModel, and is edited in Roswaal rather than as JSON by hand. Here is one built from the start:

  1. Press New node map on the top row, or right-click a folder in the Project panel, and name the map.
  2. It opens in a tab of its own: the tree on the left, the Inspector on the right. A new map starts with ServerScriptService, filled from src.
  3. With DataModel selected, Add service… adds a service under it. Pick ReplicatedStorage.
  4. Select ReplicatedStorage and press Add folder.
  5. Name the folder in Name.
  6. Set Path to the folder on disk that fills it. A folder under src that is not there yet is made when the map is written.
  7. The project file shows what the map writes, with the selected row's lines lit.
  8. Press Write project file, or Ctrl + S. In Dynamic mode, saving the map writes it.

What a graph compiles to

The file is named after the graph, and its ending comes from the script kind, chosen in the Inspector with nothing selected. The ending is how Rojo knows which class of instance to make.

KindFileIn Studio
ScriptGreeter.server.luauA Script, running on the server
LocalScriptGreeter.client.luauA LocalScript, running on a player's machine
ModuleScriptGreeter.luauA ModuleScript, run by whatever requires it

Compiling

What it compiles
Compile script, or Ctrl + SThe open graph
Compile projectEvery graph, then every node map
Compile: DynamicEach graph as you edit it, and any that change on disk — after a git pull, say
roswaal compileEverything, or the one graph or map you give it
roswaal watchThe same, without the editor

A graph with errors writes nothing; warnings do not stop it. With format on and StyLua on your PATH, the file is formatted as it is written. If StyLua refuses it, it is written unformatted and the compile says why.

In either mode, an open graph whose file changes on disk takes the new version. If it has edits that are not saved yet, you are asked which to keep.

Generated files

A generated file starts with a header naming its graph and a hash of what was written. Roswaal will not overwrite a file whose hash no longer matches — one edited by hand — or a file it did not write.

Danger

To overwrite one anyway, click overwrite in the compile results, or run roswaal compile --force. The hand edit is lost.

Moving and deleting graphs

Rename a graph, move it or change its kind, and its next compile removes the file it used to write.

A generated file whose graph is gone is stale, and Rojo goes on syncing it. The compile results list stale files with a remove link. From the command line, roswaal prune lists them and roswaal prune --yes removes them.

Building a node map

A .nodemap says where your files land in the DataModel, and compiles to a Rojo project file — default.project.json unless you change it. You edit the tree in Roswaal rather than the JSON by hand.

Tycoon
▸DataModelDataModel
▸ReplicatedStorage
SharedFoldersrc/Shared
▸ServerScriptService
ServerFoldersrc/Server

This map

Instance

Ignore paths

Globs under this instance's path that Rojo should skip, e.g. shared/** — how you stop a nested mapping syncing twice.

Project file

Written to default.project.json when this map is compiled.

Project-wide ignores

Passed to Rojo as globIgnorePaths, unanchored.

{  "name": "Tycoon",  "tree": {    "$className": "DataModel",    "ReplicatedStorage": {      "Shared": {        "$path": "src/Shared"      }    },    "ServerScriptService": {      "Server": {        "$path": "src/Server"      }    }  }}
  • The treeEvery instance the map describes. Pick one and the Inspector follows.
  • DescribesWhether this is a DataModel for Roblox or a filesystem for Lune. It decides what the rest of the panel is.
  • NameThe instance's name in the DataModel.
  • ClassBlank on a service, because Rojo infers it from the key and rejects it being said twice.
  • PathThe folder or file on disk whose contents fill this instance.
  • Ignore unknownRojo leaves alone anything in Studio that it did not put there.
  • Ignore pathsGlobs under this instance's path that Rojo should skip.
  • Add folder, Add service, DeleteBuild the tree. Services can only be added to the root.
  • OutputWhere the project file is written, relative to the project root.
  • Project-wide ignoresPassed to Rojo as globIgnorePaths, unanchored.
  • The project fileWhat the map compiles to. Selecting a row lights the lines that row writes.
The real panel. Select a row and the Inspector fills with that instance's fields, while the project file scrolls to the lines the row writes. A row lights its own lines and not its children's — they are rows too. The fields are filled rather than editable: this is the editor demonstrating itself, not a scratch project.

Two things in that file are worth naming, because both are Roswaal leaving something out on purpose. A service carries no $className, because Rojo already knows what ReplicatedStorage is and saying it again is something Rojo rejects. And Shared is a Folder in the tree with no $className in the file, because a path pointing at a directory already implies one.

Select an instance to edit it. Drag the line between the tree and the Inspector to resize them.

FieldWhat it does
NameThe instance's name in the DataModel
ClassBlank for a service, because Rojo already knows what ServerScriptService is. Otherwise Folder, Model, Configuration, ScreenGui, Part or Tool
PathThe folder or file on disk that fills the instance. A folder under src is made when the map is written, with its mirror under .roswaal/scripts for the graphs; anything else is marked when Roswaal cannot find it
Ignore unknownRojo leaves alone anything in Studio that it did not put there
Ignore pathsFiles under the path that Rojo should skip. Start one with / to write it from the project root

Add folder and Add service build the tree. Under Project file, Output is where the file is written and Project-wide ignores go to Rojo as written. The JSON it will write is shown underneath, with anything wrong — an instance with no name, or two with the same one.

Info

In Dynamic mode a saved map rewrites its project file. Write project file, Compile project and roswaal compile also make the folders it syncs, and move a folder whose path you changed to the new path, with its graphs. A project file Roswaal did not write needs --force.

Warning

A graph in a folder no map syncs is listed in Script analysis, under Project, as unsynced: its Luau is written, but Rojo never sees it.

Requiring a module

A map is also how Roswaal knows where a file ends up. Drag a graph or a .luau from the project tree onto the canvas, and it offers Require Module with the path filled in — src/ReplicatedStorage/Shared/Greeter.luau becomes ReplicatedStorage.Shared.Greeter — or Instance for a reference to it. If no map covers the file, it says so.

An existing game

A Rojo project or a place you already have becomes a Roswaal project on Places and Rojo projects, which also covers browsing the place and writing scripts back into it. Packages are on Wally packages.

Last reviewed 11 September 2026 by @neopolitans