Skip to content

Luau Run · Guides · Configuration

Project settings

Settings come from three places:

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:

luau-run.toml
[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.

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.

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.

[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.

[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.

[tools] names the versions the project runs on:

luau-run.toml
[tools]
lute = "1.0.0"
jest-portable = "0.3.0"
  • lute is a Lute version this Luau Run knows. After setting or changing it, run luau-run setup in the project’s folder. It installs that Lute and builds the Jest runner for it.
  • jest-portable is the package’s own version, not its display name 3.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 setup names 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.20261009
luau-run setup

Rojo 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