Development documentation may include features that are not in the latest release. Read the Lawn 0.8.1 guide.
Complete Example
Example template
This page walks through a complete template that uses every major feature. It covers a multi-service app with a PostgreSQL database, generated secrets, user-provided variables, config options (a log level picker and a boolean toggle), health checks, notices, environment metadata, init files, resource limits, and localization.
locales/en.json provides configuration and extension strings. App names, taglines, and descriptions remain in manifest.yaml.Directory Structure
apps/
└── example-app/
├── manifest.yaml
├── icon.svg
├── locales/
│ └── en.json
├── lawn-compose/
│ └── compose.yaml
└── init-files/
└── custom.config.php
manifest.yaml
The manifest defines how the app appears in the catalog.
id: example-app
name: Example App
tagline: A full-featured example template
description: |
An example app that demonstrates all Lawn template features.
**Highlights:**
Multi-service architecture with a PostgreSQL database,
generated database credentials, and health monitoring.
symbolFallback: app.badge.checkmark
category: Utilities
compatibility:
minLawnVersion: 0.2.0
tags:
- example
- demo
features:
- User-provided admin password
- PostgreSQL database with health checks
- Configuration file injection
links:
- url: https://github.com/example/example-app
type: github
- url: https://example.com/docs
type: documentation
webPort: 8080
lawn-compose/compose.yaml
The compose file defines the services, variables, and Lawn extensions. Its display names, descriptions, and labels live in the localization file.
x-lawn:
compatibility:
minLawnVersion: 0.2.0
config:
POSTGRES_PASSWORD:
source: generatedSecret
format: alphanumeric
length: 32
SECRET_KEY:
source: generatedSecret
format: alphanumeric
length: 50
ADMIN_PASSWORD:
source: userProvided
required: true
LOG_LEVEL:
value: info
weight: 10
options:
debug:
compose:
services:
app:
environment:
LOG_LEVEL: debug
info:
compose:
services:
app:
environment:
LOG_LEVEL: info
warning:
compose:
services:
app:
environment:
LOG_LEVEL: warning
ENABLE_SIGNUP:
inputType: boolean
value: true
weight: 20
options:
"true":
compose:
services:
app:
environment:
ENABLE_SIGNUP: "true"
"false":
compose:
services:
app:
environment:
ENABLE_SIGNUP: "false"
services:
app:
image: example/app:1.0.0
depends_on:
- db
environment:
DATABASE_URL: "postgres://postgres:${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}@db:5432/app"
SECRET_KEY: "${SECRET_KEY:?SECRET_KEY is required}"
ADMIN_USER: admin
ADMIN_PASSWORD: "${ADMIN_PASSWORD:?ADMIN_PASSWORD is required}"
TZ: "${TIMEZONE:-UTC}"
PUID: "${UID:-1000}"
PGID: "${GID:-1000}"
volumes:
- "./data:/app/data"
- "./config:/app/config"
ports:
- "8080:8080"
deploy:
resources:
limits:
memory: 1024M
x-lawn:
healthChecks:
- id: web-ui
type: http
path: /health
expectedStatus: 200
notices:
- id: login-credentials
style: info
elements:
- id: username
type: field
value: admin
- id: password
type: field
source: ADMIN_PASSWORD
container: app
- id: change-password
type: text
environment:
ADMIN_USER:
TZ:
PUID:
PGID:
initFiles:
- source: "custom.config.php"
containerPath: "/app/config/custom.config.php"
createDirectories:
- "./data/uploads"
- "./data/cache"
db:
image: postgres:15
environment:
POSTGRES_DB: app
POSTGRES_USER: postgres
POSTGRES_PASSWORD: "${POSTGRES_PASSWORD:?POSTGRES_PASSWORD is required}"
PGDATA: /var/lib/postgresql/data/pgdata
volumes:
- "./postgres:/var/lib/postgresql/data"
healthcheck:
test: ["CMD", "pg_isready", "-U", "postgres"]
interval: 10s
timeout: 5s
retries: 5
x-lawn:
healthChecks:
- id: db-ready
type: command
command: ["/bin/sh", "-c", "pg_isready -U postgres"]
environment:
POSTGRES_DB:
POSTGRES_USER:
PGDATA:
locales/en.json
The localization file provides configuration and extension strings. Keys match the variable names, health check IDs, notice IDs, and element IDs from the YAML.
{
"config": {
"POSTGRES_PASSWORD": {
"displayName": "Database Password",
"description": "PostgreSQL superuser password. Auto-generated during install."
},
"SECRET_KEY": {
"displayName": "Secret Key",
"description": "Application secret key for session signing."
},
"ADMIN_PASSWORD": {
"displayName": "Admin Password",
"description": "Choose the admin account password in Edit Configuration before starting the app."
},
"LOG_LEVEL": {
"displayName": "Log Level",
"description": "Controls how much detail the application logs.",
"options": {
"debug": { "label": "Debug" },
"info": { "label": "Info" },
"warning": { "label": "Warning" }
}
},
"ENABLE_SIGNUP": {
"displayName": "Public Sign-up",
"description": "Allow new users to create accounts.",
"options": {
"true": { "label": "On" },
"false": { "label": "Off" }
}
}
},
"services": {
"app": {
"environment": {
"ADMIN_USER": {
"description": "Username for the admin account."
},
"TZ": {
"description": "Timezone for date display and scheduling."
},
"PUID": {
"description": "User ID for file ownership inside the container.",
"group": "Permissions"
},
"PGID": {
"description": "Group ID for file ownership inside the container.",
"group": "Permissions"
}
},
"healthChecks": {
"web-ui": {
"description": "Web UI is accessible and responding."
}
},
"notices": {
"login-credentials": {
"title": "Login Credentials",
"elements": {
"username": { "label": "Username" },
"password": { "label": "Password" },
"change-password": { "content": "Change these in **Settings > Security** after your first login." }
}
}
}
},
"db": {
"environment": {
"POSTGRES_DB": {
"description": "Name of the PostgreSQL database."
},
"POSTGRES_USER": {
"description": "PostgreSQL username."
},
"PGDATA": {
"description": "Data directory inside the container. Do not change."
}
},
"healthChecks": {
"db-ready": {
"description": "Database is accepting connections."
}
}
}
}
}
init-files/custom.config.php
Init files are copied into the container's volume mounts before each start. The containerPath must fall within a declared volume mount.
<?php
// This file is injected by Lawn on every container start.
// It reads configuration from environment variables set by the compose file.
$config = [
'database' => getenv('DATABASE_URL'),
'timezone' => getenv('TZ') ?: 'UTC',
];
What Each Feature Does
| Feature | Where | Purpose |
|---|---|---|
x-lawn.compatibility | Top-level | Minimum Lawn version required for this template |
x-lawn.config | Top-level | Declares secrets, user-provided values, and config options |
generatedSecret | Config | Random password created at install time |
userProvided | Config | Editable value supplied through Edit Configuration after installation |
required: true | Config | Active setting must have a nonempty value before startup |
| Config options | Config | Selectable choices with compose overlays |
inputType: boolean | Config | Toggle switch for on/off settings |
weight | Config | Display ordering in the settings UI |
locales/en.json | Localization | Display names, descriptions, option labels, notice strings |
| System variables | Environment | TIMEZONE, UID, GID (always available) |
healthChecks | Per-service | HTTP and command checks for readiness |
notices | Per-service | Dismissible banners with credentials and guidance |
environment | Per-service | Format hints for env vars |
initFiles | Per-service | Config files injected from template into volumes |
createDirectories | Per-service | Host directories created before container start |
deploy.resources.limits | Per-service | Memory and CPU constraints |
After installation, enter ADMIN_PASSWORD in Edit Configuration, save, then click Start. Its required: true declaration blocks startup until a value is supplied. Lawn generates POSTGRES_PASSWORD and SECRET_KEY; the login notice shows the admin password you chose.
Testing
The example/app:1.0.0 image and its URLs are illustrative. Replace them with your app's real image, endpoints, and configuration before trying to run this template.
Run the Compose syntax check with disposable variable values, then follow the local-catalog testing workflow. Install a disposable instance, complete Edit Configuration before Start, use the app, and verify that data persists after a stop and start. Remove the instance and local catalog registration when finished.
lawn template validate and lawn template test are planned and are not available in the current release.