Docs
Configuration
Reference

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

All Lithos commands accept a PROJECT argument and resolve it in this order:

  1. If PROJECT is omitted, the current directory is the project.
  2. If PROJECT is a directory, Lithos searches it for one of: lithos.yml, lithos.yaml, lithos.json, lithos.luau, lithos.lua, then legacy mantle.yml, mantle.yaml.
  3. If PROJECT is 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:

    project/lithos.yml
    target:
      experience:
        configuration:
          icon: marketing/game-icon.png
          thumbnails:
            - marketing/thumbnail-1.png
            - marketing/thumbnail-2.png
        places:
          start:
            file: game.rbxl

    The 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).

    project/lithos.yml
    outputs:
      writeDir: src/shared/generated
      outputName: lithosOutputs
      format: luau
      robloxTs: true

    Supported properties

    PropertyTypeDescription
    pathstringFull output file path. Mutually exclusive with writeDir + outputName.
    writeDirstringProject-relative directory. Used with outputName.
    outputNamestringFile name. Extension is added from format if missing.
    formatjson | yaml | yml | lua | luauOutput format.
    robloxTsbooleanWrite 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.ymllithos.yamllithos.json, then lithos.luaulithos.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).

    project/lithos.luau
    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 config

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

    project/lithos.luau
    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:

    1. Lune evaluates the script and returns a table.
    2. Lithos converts the table to JSON internally and validates it against the same schema used for YAML and JSON.
    3. 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.

    Next steps