Configuration
Lithos configs can be written in YAML, JSON, or Luau / Lua. This page
covers file discovery, path resolution, outputs defaults, scripting
with Lune, and schema tooling.
Looking for every supported key? Jump straight to the Configuration Reference.
Configuration file
Lithos uses a single config file in your project root.
./lithos.ymlAll Lithos commands accept a PROJECT argument and resolve it in this
order:
- If
PROJECTis omitted, the current directory is the project. - If
PROJECTis a directory, Lithos searches it for one of:lithos.yml,lithos.yaml,lithos.json,lithos.luau,lithos.lua, then legacymantle.yml,mantle.yaml. - If
PROJECTis a file, Lithos uses it directly. Explicit paths can point to YAML, JSON, Luau, or Lua.
When more than one discovered file exists, declarative formats win over
scripts (.yml > .yaml > .json > .luau > .lua), and lithos.*
always wins over the legacy Mantle names.
File path resolution
All paths and globs in your config resolve relative to the config file, not the shell working directory.
For the layout:
- lithos.yml
- game.rbxl
- game-icon.png
- thumbnail-1.png
- thumbnail-2.png
You would write:
target:
experience:
configuration:
icon: marketing/game-icon.png
thumbnails:
- marketing/thumbnail-1.png
- marketing/thumbnail-2.png
places:
start:
file: game.rbxlThe same rule applies to .env: Lithos loads the file next to the
resolved config, plus any .env in the current working directory.
Outputs defaults
lithos outputs can read defaults from the project file with either
the outputs block (camelCase) or the codegen alias (snake_case).
outputs:
writeDir: src/shared/generated
outputName: lithosOutputs
format: luau
robloxTs: trueSupported properties
| Property | Type | Description |
|---|---|---|
path | string | Full output file path. Mutually exclusive with writeDir + outputName. |
writeDir | string | Project-relative directory. Used with outputName. |
outputName | string | File name. Extension is added from format if missing. |
format | json | yaml | yml | lua | luau | Output format. |
robloxTs | boolean | Write a .d.ts sidecar when the output is Luau. |
CLI flags such as --output, --format, and --roblox-ts always
override the values in outputs. When robloxTs is true and no
format is set, Lithos defaults to .luau.
YAML and JSON
Lithos accepts YAML and JSON interchangeably. Auto-discovery prefers
lithos.yml → lithos.yaml → lithos.json, then lithos.luau →
lithos.lua, then the legacy Mantle names. JSONC and YAML
anchors-in-comments are not supported.
If you need a YAML refresher, see Learn YAML in Y Minutes (opens in a new tab) or the examples repo (opens in a new tab).
Luau and Lua
For projects whose configuration would otherwise be repetitive (many similar places, programmatically derived asset lists, environment-driven branches), Lithos can evaluate a Luau or Lua file instead of a static YAML / JSON document.
Luau configs are executed by Lune (opens in a new tab),
an external Luau runtime. Install Lune (via
Aftman (opens in a new tab),
Foreman (opens in a new tab), or your package manager)
and make sure the lune binary is on PATH. To pin a specific
binary, set LITHOS_LUNE=/path/to/lune.
Your script must return a table whose shape matches the same schema
the YAML and JSON configs use, or a table of the form
{ config = <table>, ... } (which leaves room for hooks, see below).
local environments = { "production", "staging", "dev" }
local config = {
environments = {},
target = {
experience = {
places = {
start = { file = "game.rbxl" },
},
},
},
}
for _, label in ipairs(environments) do
table.insert(config.environments, {
label = label,
branches = { label == "production" and "main" or label },
})
end
return configBecause the file is just Luau, you can require shared helpers, read
environment variables via @lune/process, and pull in JSON / TOML
snippets through @lune/serde — exactly like any other Lune script.
Hooks
Return a table with named hook functions alongside config to react
to Lithos lifecycle events. Today Lithos invokes one hook synchronously
at load time; additional hooks are recorded so future deploy steps can
route into them.
return {
config = {
environments = { { label = "production", branches = { "main" } } },
target = {
experience = {
places = { start = { file = "game.rbxl" } },
},
},
},
-- Runs immediately after Lithos evaluates the config. Return a new
-- table to replace the loaded config, or `nil` to leave it as-is.
onConfigLoaded = function(config)
if os.getenv("CI") then
config.environments[1].branches = { "main", "release/*" }
end
return config
end,
-- Registered for future deploy lifecycle integration.
onBeforeDeploy = function() end,
onAfterDeploy = function() end,
}Hook functions must use the on<Name> naming convention so Lithos
can distinguish them from helpers that happen to live at the top
level. Function values found anywhere else are stripped from the
config before validation.
If Lune cannot start, the user script raises an error, or the returned table does not match the Lithos schema, Lithos surfaces the failure together with the offending config path and Lune's stderr.
Editor schemas
The published JSON schema powers autocomplete and validation in VS Code, JetBrains IDEs, and anywhere else with YAML/JSON schema support.
In VS Code, install the YAML extension (opens in a new tab) for YAML files and add the snippet below to your settings:
VS Code YAML files
"yaml.schemas": {
"https://siriuslatte.github.io/lithos/previews/pr-25/schemas/v0.4.0-beta.1/schema.json": ["lithos.yml", "mantle.yml"]
}VS Code JSON files
"json.schemas": [
{
"fileMatch": ["lithos.json"],
"url": "https://siriuslatte.github.io/lithos/previews/pr-25/schemas/v0.4.0-beta.1/schema.json"
}
]What about Luau and Lua?
The JSON schema validates the shape of a Lithos config — string vs. number, required keys, allowed enum values. A Luau / Lua script is code, not data, so editors cannot apply the JSON schema to it the way they do to YAML or JSON.
Validation still happens, just at a different point:
- Lune evaluates the script and returns a table.
- Lithos converts the table to JSON internally and validates it against the same schema used for YAML and JSON.
- Any schema violation is reported with the offending config path and the failing field, the same way YAML and JSON errors are reported.
That means a lithos.luau file with a misspelled key or a wrong-typed
value will fail at config-load time with a normal Lithos error — not
silently produce a broken deploy.
For editor support inside the .luau file itself, use
luau-lsp (opens in a new tab) the same way you
would for any other Lune script. It type-checks Luau syntax, function
calls, and required modules, but it does not know about the Lithos
config shape — treat the returned table as a plain Luau table and rely
on Lithos's runtime validation for shape errors.
If you want schema-driven autocomplete while authoring, write the
body of your config in lithos.json (or lithos.yml) and only reach
for lithos.luau when you need real logic — environment fan-out,
conditional branches, computed asset lists, or hooks.