Variables
Lawn's configuration system handles three categories of values:
- Secrets — Generated passwords and API keys
- User input — Settings edited after installation
- Configuration — Selectable options with typed controls (toggles, pickers, number fields)
Variables are defined in the template, resolved when needed, and injected into containers at startup. Display strings (displayName, description, option labels) live in the localization file, not in the YAML.
Variable Types
| Type | Declared in | Resolved | Use case |
|---|---|---|---|
| Generated Secret | x-lawn.config | When first needed | Passwords, API keys, tokens |
| User Provided | x-lawn.config | At config change | Editable app settings |
| Config Option | x-lawn.config | At config change | Selectable choices with compose overlays |
| System | Built-in | At startup | Timezone, UID, GID |
| Port | Built-in | At startup | Host port assignments |
For per-service environment metadata (format hints, descriptions), see Environment Metadata.
Generated Secrets
A random value created when its config key is first needed. Use generated secrets for passwords, API keys, and tokens that users don't need to choose.
x-lawn:
config:
SECRET_KEY:
source: generatedSecret
format: alphanumeric
length: 50
| Field | Default | Description |
|---|---|---|
source | — | Must be generatedSecret |
format | alphanumeric | Output format: alphanumeric, hexadecimal, or base64 |
length | 32 | Output characters for alphanumeric and hexadecimal values, from 1 through 4096 |
bytes | — | Random input bytes for Base64, from 1 through 4096 |
formatOptions | [] | Base64 changes: urlSafeAlphabet and omitPadding |
Format names and format options are case-sensitive. Omitting format remains supported and selects alphanumeric; if length is also omitted, it defaults to 32. New declarations should state their format explicitly.
Alphanumeric
alphanumeric produces uppercase letters, lowercase letters, and decimal digits. length is optional and defaults to 32.
x-lawn:
config:
DATABASE_PASSWORD:
source: generatedSecret
format: alphanumeric
length: 48
Hexadecimal
hexadecimal produces lowercase characters in [0-9a-f]. length is the number of output characters, not a byte count, and defaults to 32. Odd lengths are valid.
For example, a 64-character Garage RPC secret can be declared as:
x-lawn:
config:
GARAGE_RPC_SECRET:
source: generatedSecret
format: hexadecimal
length: 64
Base64
base64 encodes the requested number of random bytes. It requires bytes and does not allow length, because the encoded output length depends on the byte count and padding.
With no formatOptions, Lawn uses the standard Base64 alphabet and includes padding. Lawn never inserts line breaks.
| Option | Effect |
|---|---|
urlSafeAlphabet | Replaces + and / with - and _ |
omitPadding | Removes trailing = padding characters |
The options are independent and may be combined in any order:
x-lawn:
config:
API_TOKEN:
source: generatedSecret
format: base64
bytes: 32
formatOptions:
- urlSafeAlphabet
- omitPadding
Generation fields are valid only when source is generatedSecret. bytes and formatOptions are valid only with Base64, while length is valid only with alphanumeric and hexadecimal. Option names must use the spelling shown above and may not be repeated.
Lawn creates a secret only when the instance has no stored value for that config key. The stored value survives container recreation, app and Lawn restarts, and template updates. Changing the format, count, options, or source later does not rotate or check an existing value. Renaming the YAML config key creates a new secret because the key is the value's identity.
User Provided
A setting edited through Edit Configuration or lawn app config after installation.
x-lawn:
config:
ADMIN_PASSWORD:
source: userProvided
required: true
Required values
required is an optional boolean. Omission means optional, regardless of source. An active required: true setting needs a value on every start. Missing values and empty strings fail the requirement; a nonempty template value, boolean false, and numeric 0 satisfy it.
Requirements are checked after defaults and config options resolve. Inactive option fields do not block startup. A Compose substitution fallback does not supply a config value; declare defaults with value.
Users can select an option and fill in its settings in one edit:
lawn app install github-actions-runner --name ci
lawn app config set ci RUNNER_SCOPE=repo REPO_URL=https://github.com/your-org/your-repo
Use Edit Configuration for sensitive values to keep them out of shell history and process arguments.
Config Options
Config variables can define selectable options, where each option carries a compose overlay that Lawn merges as an additional layer. This gives users a curated set of choices instead of raw environment variable editing.
x-lawn:
config:
DIFFICULTY:
value: easy
weight: 10
options:
peaceful:
compose:
services:
minecraft:
environment:
DIFFICULTY: peaceful
easy:
compose:
services:
minecraft:
environment:
DIFFICULTY: easy
normal:
compose:
services:
minecraft:
environment:
DIFFICULTY: normal
hard:
compose:
services:
minecraft:
environment:
DIFFICULTY: hard
Each option's compose block is a standard compose document fragment. When the user selects "hard", Lawn merges that fragment into the active configuration — setting DIFFICULTY: hard in the container's environment.
Input Types
The inputType field controls how the UI renders the config variable:
inputType | UI Control | Options Required |
|---|---|---|
| (omitted) | Picker (if options) or text field | No |
boolean | Toggle switch | Yes (exactly 2, keyed "true" and "false") |
number | Number input field | No |
text | Text input field | No |
Boolean toggle — use inputType: boolean with exactly two options:
PVP:
inputType: boolean
value: true
weight: 30
options:
"true":
compose:
services:
minecraft:
environment:
PVP: "TRUE"
"false":
compose:
services:
minecraft:
environment:
PVP: "FALSE"
The localization file provides labels for each option (e.g., "On"/"Off" or "Enabled"/"Disabled").
Number input — use inputType: number for integer values:
SPAWN_PROTECTION:
inputType: number
value: 16
weight: 170
Text input — use inputType: text for free-form strings:
SEED:
inputType: text
value: ""
weight: 130
Display Ordering
The weight field controls the display order in the UI. Lower values appear first. Variables with the same weight are sorted alphabetically. The default is 0.
x-lawn:
config:
DIFFICULTY:
weight: 10 # Appears first
HARDCORE:
weight: 20 # Appears second
PVP:
weight: 30 # Appears third
Config Variable Fields
| Field | Default | Description |
|---|---|---|
source | — | generatedSecret or userProvided (omit for config options without a source) |
required | false | Active setting must have a value on every start |
format | alphanumeric | Generated-secret output: alphanumeric, hexadecimal, or base64 |
length | 32 | Output characters for alphanumeric and hexadecimal generated secrets |
bytes | — | Random input bytes for Base64 generated secrets |
formatOptions | [] | Base64 changes: urlSafeAlphabet and omitPadding |
value | — | Default value (string, boolean, or number) |
inputType | — | UI control: boolean, number, or text |
weight | 0 | Display order (lower values first) |
options | — | Map of option values to compose overlays |
System Variables
These are always available in every template — Lawn injects them automatically.
| Variable | Description | Example |
|---|---|---|
TIMEZONE | User's IANA timezone | Europe/Amsterdam |
UID | Host user ID | 501 |
GID | Host group ID | 20 |
Use them with fallbacks: ${TIMEZONE:-UTC}, ${UID:-1000}, ${GID:-1000}.
x-lawn.config — they are injected by the engine and always available.Port Variables
The engine injects HOST_PORT_<N> for each exposed port at container start:
| Variable | Description |
|---|---|
HOST_PORT_<N> | Resolved host port for container port N |
For example, if container port 8080 maps to host port 51811, then HOST_PORT_8080=51811.
Usage in Compose Files
Use substitution syntax in environment values to reference variables:
services:
db:
image: postgres:15
environment:
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-changeme}
TZ: ${TIMEZONE:-UTC}
Lawn substitutes the real values at runtime. The :-default fallback keeps compose files valid for standalone use with docker compose up.
Substitution Syntax
Lawn supports the full Docker Compose variable substitution syntax:
| Syntax | Description |
|---|---|
$VAR or ${VAR} | Substitute the value of VAR |
${VAR:-default} | Use default if VAR is unset or empty |
${VAR-default} | Use default if VAR is unset |
${VAR:+replacement} | Use replacement if VAR is set and non-empty |
${VAR+replacement} | Use replacement if VAR is set |
${VAR:?error} | Error if VAR is unset or empty |
${VAR?error} | Error if VAR is unset |
$$ | Literal $ (escaped) |
${VAR:-default}. Always provide a fallback so the compose file works standalone with docker compose config.When to Use What
| Scenario | Approach |
|---|---|
| Passwords and secrets the user doesn't choose | generatedSecret in x-lawn.config |
| Values the user must provide (API keys, repo URLs) | userProvided in x-lawn.config |
| Selectable settings with discrete choices | Config options with compose overlays |
| Boolean toggles (on/off features) | inputType: boolean with two options |
| Numeric settings (ports, distances, limits) | inputType: number |
| Free-form text (world names, seeds) | inputType: text |
| Static settings that need a description in the UI | Per-service x-lawn.environment (Environment Metadata) |
| Timezone, user/group IDs | System variables (always available) |
| Dynamic port assignments | Port variables (always injected) |