Project settings
Settings come from three places:
- the project’s
luau-run.toml, which this page describes - your own
config.toml, your defaults for every project - environment variables, which win over both for the paths they name
luau-run doctor shows the settings and tools in effect, and where each came
from.
luau-run.toml sits in the project’s folder, and luau-run init writes one.
luau-run test and the project’s commands read it only from the folder they
run in.
| Key | What it holds |
|---|---|
[test] |
How tests are found and run. |
[tools] |
The Lute and Jest-Portable versions the project runs on. |
[commands] |
The project’s own commands, run as luau-run <name>. |
luau-run-version |
The minimum Luau Run version the project needs. |
schema-version |
The file’s schema version. When given, it must be 1. |
Unknown keys, values out of range, and a file that is not valid TOML are refused, naming the key or line.
Set luau-run-version when the project needs a newer Luau Run, such as for a
setting older versions do not have. Anyone on an older version is then told to
update, instead of getting an unknown-setting error. Put it at the top of the
file, above any table, as in luau-run-version = "0.1.0".
An example:
[test]roots = ["tests"]exclude-directories = ["node_modules", "luau_packages", "_Generated"]default-runtime = "lute"worker-count = 1
[[test.runtime-rules]]glob = "tests/**/*.spec.luau"runtime = "lute"
[[test.runtime-rules]]glob = "tests/roblox/**/*.spec.luau"runtime = "roblox"Specs under tests/roblox run in Roblox Studio and the rest on Lute, because
the last matching rule wins. This exclude-directories replaces the default
list rather than adding to it.
Test settings
Section titled “Test settings”| Setting | Values | Default | What it does |
|---|---|---|---|
roots |
Up to 64 paths from the project’s folder | ["tests"] |
Where tests are looked for. Each must exist. A path on the command line replaces them for one run. |
exclude-directories |
Up to 64 folder names | .git, node_modules, luau_packages, _Generated, _Vendor, _Baked, _Cache |
Folders skipped at any depth. Setting it replaces the whole default list. On Windows, names match ignoring case. |
default-runtime |
lute, roblox or luau |
None | The runtime when no header, option or rule picks one. luau is accepted, but its files are refused. |
runtime-rules |
Up to 256 glob and runtime pairs |
None | The runtime by path. The last rule that matches wins. |
runner-rules |
Up to 256 glob and runner pairs |
None | The runner by path: jest, script or one of runners. The last rule that matches wins. |
runners |
Up to 64 named runners | None | The project’s own custom runners. |
worker-count |
1 to 64 | 1 | How many workers run at once. |
spec-timeout-seconds |
1 to 2,147,483 | 120 | The limit for each test file. |
when-spec-times-out |
skip, stop or restart |
skip |
What happens to the rest of a file’s process when the file passes its limit. |
timeout-seconds |
1 to 2,147,483 | None: the per-file limits bound the run | The limit for the whole run. |
when-spec-refused |
run-others or refuse-run |
run-others |
With run-others, Luau Run refuses only that file and runs the rest. With refuse-run, one refused file refuses the whole run. |
progress |
auto, always, never or failures |
auto |
Whether each file gets a line on standard error as it finishes. |
jest-portable |
A table | See Jest settings. | |
roblox-studio |
A table | See Studio settings. |
Choosing a lane and a runner
explains how a file’s runtime is picked, and
Time limits explains the limits.
--workers, --progress and --runtime override their settings for one run.
A rule’s glob matches a file’s path from the project’s folder, with forward
slashes, such as tests/roblox/**. It cannot start with / or ./ or contain
a backslash, and on Windows it matches ignoring case.
Which files are found
Section titled “Which files are found”Only *.spec.luau and *.test.luau files under the roots are tests. Below a
root, Luau Run skips hidden folders, the folders exclude-directories names,
and anything a .gitignore file ignores. A root you name is read even if it is
ignored.
Luau Run does not follow symbolic links, and refuses a root that is one. A file under two overlapping roots counts once. The files found are sorted by path.
Jest settings
Section titled “Jest settings”[test.jest-portable] takes three settings:
| Setting | Values | Default | What it does |
|---|---|---|---|
surface |
full or test-globals |
full |
How much of Jest a spec on Lute gets. |
project-jest-globals |
replace or keep |
replace |
Studio only: whether requiring the project’s own Jest globals gets Luau Run’s copy instead. |
project-jest-globals-file |
A path to a .luau or .lua file |
None | Studio only: names the project’s Jest globals module by path. Refused with keep. |
The last two are described in Jest globals in Studio. An empty table is refused: leave it out, or set at least one key.
On Lute, surface = "test-globals" loads only Jest’s test runner and test
globals. Declarations, assertions, hooks, mocks and fake timers work as on the
full surface. A test that reads an export only the full surface has, such as
runCLI, fails, and the failure names surface = "full" as the fix. Luau Run
refuses specs in Studio under test-globals.
Studio settings
Section titled “Studio settings”[test.roblox-studio] takes these settings:
| Setting | Values | Default | What it does |
|---|---|---|---|
rojo-project |
A path to a *.project.json that builds a place |
None | The Rojo project that builds the test place. Needed for requires by instance path. |
data-model |
run-server or edit |
run-server |
Which Studio DataModel the specs run in. --studio-data-model overrides it. |
visibility |
invisible or visible |
invisible |
Whether Studio’s window shows. --studio-visibility overrides it. |
shutdown |
completed-stop or normal |
completed-stop |
How Studio is ended. --studio-shutdown overrides it. |
runner-service |
TestService, ServerStorage or ReplicatedFirst |
The first your project does not declare | Where Luau Run’s _LuauRun folder goes when the test place is your whole place. |
boot-timeout-seconds |
1 to 2,147,483 | 60 | How long Studio has to start the tests. A Studio that is signed out or showing a dialog never starts them. |
A table that sets some of these keeps the default for the rest. An empty one is refused. Roblox Studio lane and Data models describe what each one does.
Tool versions
Section titled “Tool versions”[tools] names the versions the project runs on:
[tools]lute = "1.0.0"jest-portable = "0.3.0"luteis a Lute version this Luau Run knows. After setting or changing it, runluau-run setupin the project’s folder. It installs that Lute and builds the Jest runner for it.jest-portableis the package’s own version, not its display name3.20.0+0.3.0. Each Luau Run carries one Jest-Portable. If the project names another, Luau Run refuses its Jest specs and still runs its script tests.luau-run setupnames the setting to change.
For a Lute release this Luau Run does not know, luau-run pin lute records its
hashes in a [tools.lute] table. Give the version without the tag’s leading
v, then run luau-run setup in the project’s folder:
luau-run pin lute 1.0.1-nightly.20261009luau-run setupRojo comes from the project’s Rokit or Aftman pin, Luau Run finds Studio on
each computer, and the supervisor comes with
Luau Run. How each tool is chosen has the full order.
luau-run.toml cannot name a program by path. Set paths in
your own settings or a
variable.
© 2026 PRMS Developer