Templates

Contributing

GitHub
Guidelines and checklist for submitting new templates.
The catalog is community-driven. Want to add an app? Open a PR on GitHub. Support for custom catalogs from other sources is coming soon.

Templates live in the getlawn/templates repository. This page covers the conventions and requirements for contributing a new template via pull request.

Naming Conventions

App ID — Lowercase, hyphen-separated. Must match the directory name and the id field in manifest.yaml. Use the app's commonly known name (e.g., paperless-ngx, uptime-kuma, adguard-home).

Compose filenames — Use v followed by the app version: v1.0.0.yaml, v10.10.yaml, or v32.yaml. The version can have one, two, or three parts depending on the app's versioning scheme.

Icon Requirements

Include an icon.svg (preferred), icon.png, icon.heif, or icon.pdf in the template directory. SVG is preferred because it scales to any size. For PNG, use at least 256×256 pixels.

The icon field in manifest.yaml specifies an SF Symbol name used as a fallback when no icon file is present.

Style Guidelines

  • Localization — All user-facing strings (display names, descriptions, labels, notice titles) belong in locales/en.json, not in the YAML template.
  • Notices — Use a maximum of 2-3 per template. Reserve them for information users genuinely need to act on: login credentials, required setup steps, or warnings about values they should not change. Use info for general guidance and warning for critical actions.
  • Environment defaults — Always provide ${VAR:-default} fallbacks so the compose file works standalone with docker compose config.
  • Descriptions — Write clear, concise descriptions for variables and environment metadata. Describe what the value controls, not just what it is.
  • Display ordering — Use weight to order config variables logically. Group related settings together and put important ones first.
  • Volumes — Use relative paths (./data:/app/data) for persistent data. Avoid absolute paths unless strictly necessary.

PR Checklist

Before submitting a template, verify each item:

Manifest

  • id matches the directory name
  • name, description, icon, and category are set
  • category is one of: Documents, Media, Development, Networking, Utilities, Databases, Monitoring
  • webPort is set if the app has a web UI
  • At least one link (GitHub or documentation) is included

Compose File

  • All images use explicit version tags (no latest)
  • Compose file validates with docker compose config
  • Environment variables use ${VAR:-default} substitution with sensible defaults
  • Volumes use relative paths for persistent data
  • Ports are declared for services with a web UI

Variables and Secrets

  • Passwords and tokens use generatedSecret (not hardcoded defaults)
  • userProvided variables are only used when the user must supply the value (API keys, external URLs)
  • inputType is set for boolean and number config variables
  • Config options use compose overlays for each selectable value

Localization

  • locales/en.json exists with entries for all user-facing strings
  • Every config variable has displayName and description
  • Every config option value has a label
  • Boolean config variables have exactly 2 option labels ("true" and "false")
  • Every environment variable has a description
  • Every health check has a description
  • Every notice has a title and all elements have label/content
  • No dangling keys (JSON entries without matching YAML structures)

Health Checks

  • At least one Lawn health check (x-lawn.healthChecks) is defined for the main service
  • HTTP checks use a reliable endpoint (health or root path)
  • Database services have a standard healthcheck in the compose spec

Notices

  • Login credentials are surfaced in a notice (if applicable)
  • Notices use sourceField for dynamic values instead of hardcoding passwords
  • No more than 2-3 notices per template

Testing

  • lawn template validate . passes (catches missing localization entries)
  • lawn template test . passes (with --var for any userProvided variables)
  • All health checks pass within the default timeout