DevelopmentUnreleased

This topic is not available in this guide. You're viewing its overview.

Development documentation may include features that are not in the latest release. Read the Lawn 0.8.1 guide.

Configuration

Merging

How Lawn merges template and instance compose files.
The built-in catalog is community-driven. Want to contribute an app? Open a PR on GitHub. You can also add custom catalogs from public Git repositories or local folders in Lawn Settings.

Merging & Overrides

When a container starts, Lawn merges the template compose file with the instance override to produce the final configuration. The template defines the baseline. The instance override stores the user's customizations.

Within each service, Lawn applies these rules when both layers define a property:

PropertyMerge rule
environment mappingsMerge by variable name; the later value wins. A null value removes the variable.
portsMerge by container port, published host port, and protocol. A matching entry is replaced; other entries remain.
volumesMerge by container path. A matching mount is replaced; other mounts remain.
depends_on listsCombine service names without duplicates.
deployMerge nested mappings recursively; the later value wins on conflicts.
Other service propertiesUse the later value, including whole mappings and lists.

Merge example

The template defines this baseline:

Template
services:
  app:
    image: nginx:1.28
    environment: { KEEP: inherited, MODE: normal, REMOVE: legacy }
    ports: ["8080:80", "8443:443"]
    volumes: ["./data:/data", "./config:/config:ro"]
    depends_on: [db]
    deploy:
      resources:
        limits: { cpus: "1", memory: 256M }
    healthcheck: { test: ["CMD", "nginx", "-t"], interval: 1m }
  db:
    image: postgres:17
  cache:
    image: redis:8

The instance override changes some entries and adds others:

Instance override
services:
  app:
    environment: { MODE: fast, REMOVE: null }
    ports: ["127.0.0.1:8080:80", "9090:80"]
    volumes: ["./custom-config:/config:ro"]
    depends_on: [cache]
    deploy:
      resources:
        limits: { memory: 512M }
    healthcheck: { test: ["CMD", "nginx", "-t"], timeout: 5s }

The merged result retains the inherited environment variable, 8443:443 port mapping, data mount, dependency, and CPU limit. The port's host IP does not form part of its identity, so 127.0.0.1:8080:80 replaces 8080:80. A different published port adds another entry. The healthcheck mapping is replaced entirely, so the inherited interval is absent:

Merged result
services:
  app:
    image: nginx:1.28
    environment: { KEEP: inherited, MODE: fast }
    ports: ["127.0.0.1:8080:80", "8443:443", "9090:80"]
    volumes: ["./data:/data", "./custom-config:/config:ro"]
    depends_on: [db, cache]
    deploy:
      resources:
        limits: { cpus: "1", memory: 512M }
    healthcheck: { test: ["CMD", "nginx", "-t"], timeout: 5s }
  db:
    image: postgres:17
  cache:
    image: redis:8

Removing a Variable

Set a variable to null in the override to remove it from the merged result:

services:
  app:
    environment:
      UNWANTED_VAR: null

Replacing Entire Values

Use the !override YAML tag to replace a value entirely instead of merging. Applied to the template above, this override leaves only "9090:8080" in ports:

services:
  app:
    ports: !override
      - "9090:8080"

Use the !reset tag to remove a value entirely (the property becomes absent, rather than empty):

services:
  app:
    volumes: !reset

Variable Resolution

Template variables declared in x-lawn.config are resolved when needed. Stored values and defaults are substituted at container start using variable substitution syntax.

Config Option Layers

When a config variable uses selectable options, Lawn merges the selected option's compose overlay as an additional layer. The layers are applied bottom to top:

LayerSource
3. User overrideInstance customizations (always wins)
2. Config option overlaysOne layer per active selection
1. TemplateBase compose file from lawn-compose/

Lawn resolves config options recursively — if one option depends on another, the system iterates until the layer set stabilizes.

What Users Can Override

Through the Lawn UI or CLI, users can customize:

SettingHow it's stored
Environment variablesservices.<name>.environment entries
Port mappingsservices.<name>.ports entries
Memory limitsservices.<name>.deploy.resources.limits.memory
Dismissed noticesx-lawn.instance.dismissedNoticeIds