Development documentation may include features that are not in the latest release. Read the Lawn 0.8.1 guide.
Extensions
Lawn extensions
The Compose Specification allows custom x- prefixed keys as extensions. Lawn uses x-lawn at two levels:
- Top-level — template-wide settings like
x-lawn.configdeclarations and compatibility - Per-service — health and migration checks, environment metadata, notices, directories, init files, and guest kernel permissions
User-facing strings (descriptions, titles, labels, content) live in the localization file, not in the YAML template.
Compatibility
Declare the minimum Lawn version required to use this template. Lawn keeps newer templates visible, but replaces their install action with the required Lawn version. If the manifest and compose file both declare a minimum, Lawn uses the newer version.
x-lawn:
compatibility:
minLawnVersion: 0.2.0
| Field | Description |
|---|---|
minLawnVersion | Minimum Lawn version required (e.g., 0.2.0) |
Guest kernel settings
Set writableSysctls: true for services that need to change guest kernel settings, such as a nested Docker daemon enabling IP forwarding. This makes /proc/sys writable for that service and its pre_start steps. It defaults to false; other read-only and masked paths remain restricted. Settings affect the service's Linux VM, not the Mac's kernel.
services:
runner:
image: example/runner:1
x-lawn:
writableSysctls: true
Health Checks
Lawn-specific health checks that determine when a service is ready. These complement the standard healthcheck field from the Compose Specification. Each health check has an id used as a localization key.
services:
app:
x-lawn:
healthChecks:
- id: web-ui
type: http
path: /health
expectedStatus: 200
followRedirects: true
The description for each health check lives in locales/en.json under services.<svc>.healthChecks.<id>.description.
When expectedStatus is omitted, any response from 200 through 299 passes. Set expectedStatus when the service must return one exact status; for example, expectedStatus: 200 rejects a 201 response.
HTTP health checks:
| Field | Default | Description |
|---|---|---|
id | — | Unique identifier (localization key) |
type | — | Must be http |
path | — | URI path to check |
expectedStatus | Any 2xx | Exact HTTP status code required when set |
followRedirects | true | Follow 3xx redirects |
Command health checks:
services:
db:
x-lawn:
healthChecks:
- id: db-ready
type: command
command: ["/bin/sh", "-c", "pg_isready -U postgres"]
Timing fields (shared by both types):
| Field | Default | Description |
|---|---|---|
intervalSeconds | 30 | Seconds between checks |
timeoutSeconds | 10 | Seconds before a check times out |
retries | 3 | Additional attempts after the first probe |
startPeriodSeconds | 60 | Failure grace window; probes start immediately |
Both HTTP and command checks probe immediately and can pass during the start period. While the grace window is active, failed probes can continue beyond the retry limit. With startPeriodSeconds: 0, retries: 3 allows four attempts in total.
Migration Checks
Some apps continue migrating data after they become healthy. Add migrationCheck to a service so Lawn can wait for that work to finish before advancing past a required intermediate version listed in updateThrough.
Write a command that checks progress and can run repeatedly:
services:
app:
x-lawn:
migrationCheck:
command: [sh, /usr/local/bin/check-migrations.sh]
| Field | Default | Description |
|---|---|---|
command | Required | Nonempty executable followed by its arguments, as an array. Use an explicit shell for shell syntax. |
user | Container default | User name or numeric ID, optionally followed by :group. |
interval | 30s | Delay before repeating a pending or failed check. |
timeout | 30s | Time limit for one invocation. |
retries | 3 | Positive integer; consecutive failures before checking stops. |
For interval and timeout, use a positive whole number of seconds (30s or 30), minutes (2m), or hours (1h).
| Exit code | Meaning |
|---|---|
0 | Migration complete. |
75 | Still migrating. Resets the consecutive failure count. |
| Any other code | Failed attempt. Execution errors and timeouts also count as failures. |
The command runs inside the service with its environment. To include a check script with the template, use init files.
Environment Metadata
Metadata for environment variables declared in the service's environment: section. Provides format hints for validation.
services:
db:
environment:
POSTGRES_USER: postgres
POSTGRES_DB: app
x-lawn:
environment:
POSTGRES_USER:
format: string
POSTGRES_DB:
format: string
Environment entries can also be bare keys with no value — the key's presence registers the variable with Lawn, and descriptions come from the localization file:
x-lawn:
environment:
EULA:
TZ:
VERSION:
| Field | Description |
|---|---|
format | Validation hint: string, integer, boolean, port, or url |
Descriptions and group labels live in locales/en.json under services.<svc>.environment.<VAR>. See Localization for the full JSON structure.
Notices
Notices are dismissible banners shown on the instance detail panel after installation. Use them to surface important information: default credentials, required setup steps, or warnings about things users should not change.
Defining Notices
Notices are defined in a service's x-lawn.notices array. The YAML contains only structural fields — titles, labels, and content live in the localization file.
services:
app:
x-lawn:
notices:
- id: default-credentials
style: info
elements:
- id: username
type: field
value: admin
- id: password
type: field
source: ADMIN_PASSWORD
container: app
- id: setup-note
type: text
The corresponding localization entry provides the user-facing strings:
{
"services": {
"app": {
"notices": {
"default-credentials": {
"title": "Default Credentials",
"elements": {
"username": { "label": "Username" },
"password": { "label": "Password" },
"setup-note": { "content": "Change these in **Settings > Security** after your first login." }
}
}
}
}
}
}
Notice Fields
| Field | Description |
|---|---|
id | Unique identifier (localization key and dismissal tracking) |
style | info (blue) for general guidance, warning (orange) for critical actions |
elements | List of content blocks, each with an id |
visibleWhen | Optional condition with required variable and value, and optional container; see conditional notices |
Element Types
Text — Markdown content (provided via localization JSON):
- id: setup-note
type: text
Field — Static label-value pair with a copy button:
- id: username
type: field
value: admin
Source field — Resolves the current value of an environment variable. Uses the same type: field as static fields, but includes source to name the variable and an optional container to scope the lookup:
- id: password
type: field
source: ADMIN_PASSWORD
container: app
The source field reads the resolved value of the named variable, keeping credential notices accurate even after overrides. Set container when multiple services use the same variable name. Labels for both static and sourced fields come from the localization file.
To extract part of a compound value, set both separator and position. Lawn splits at the first occurrence of the separator. position: first returns the part before it; position: last returns the remainder. For CREDENTIALS=admin:password, these fields display admin and password:
- id: username
type: field
source: CREDENTIALS
container: app
separator: ":"
position: first
- id: password
type: field
source: CREDENTIALS
container: app
separator: ":"
position: last
Conditional notices
Use visibleWhen to show a notice only when a resolved environment variable equals the specified string. variable and value are required; container optionally scopes the lookup to a service. A missing variable hides the notice.
services:
app:
environment:
DISABLE_SIGNUPS: "false"
x-lawn:
notices:
- id: open-signups
style: warning
visibleWhen:
variable: DISABLE_SIGNUPS
value: "false"
container: app
elements:
- id: disable-signups
type: variableAction
variable: DISABLE_SIGNUPS
value: "true"
container: app
Variable action
A type: variableAction element adds a button that sets an environment variable to a specified value. Both variable and value are required strings. container is optional and targets a service's environment variable. Put the button's label in the localization file, under services.<svc>.notices.<notice-id>.elements.<element-id>.label.
In the example above, the button sets DISABLE_SIGNUPS to "true" for app. The notice then disappears because its visibility condition no longer matches.
{
"services": {
"app": {
"notices": {
"open-signups": {
"title": "Signups are open",
"elements": {
"disable-signups": { "label": "Disable signups" }
}
}
}
}
}
}
Notice Guidelines
- Use
infostyle for setup guidance andwarningfor critical actions - Notices are collected from all services in the compose file
Init Files
Init files are copied from the template into the container's volume mounts before each start. They're useful for configuration overrides that need to exist on disk when the container boots.
Init files are defined in a service's x-lawn.initFiles array:
services:
app:
x-lawn:
initFiles:
- source: "override.config.php"
containerPath: "/var/www/html/config/override.config.php"
| Field | Description |
|---|---|
source | Filename in the template's init-files/ directory |
containerPath | Absolute path inside the container |
The containerPath must fall within a declared volume mount. Lawn resolves it to a host path using the volume mapping. For example, if the volume is ./www:/var/www and the containerPath is /var/www/html/config/foo.php, the file is written to {volume_host_path}/html/config/foo.php.
Create Directories
The x-lawn.createDirectories array lists host-side directories to create before the container starts. Paths follow the same conventions as volume host paths — relative paths resolve against the instance's data/ directory.
services:
app:
x-lawn:
createDirectories:
- "./data/uploads"
- "./data/cache"
This is useful when a volume mount covers a parent directory but the container expects specific subdirectories to exist on first startup.