YAML style
How YAML examples in the documentation should look, so they are easy to read, copy, and adapt.
People copy YAML examples straight into their own configuration. When every example follows the same style, they are easier to read, easier to compare, and easier to get right the first time.
This page has two parts. The first covers plain YAML, and applies to any YAML you write. The second covers choices that are specific to Home Assistant, where the same thing can be written in more than one way.
Indent with 2 spaces.
# Good
lighting:
brightness: 80
# Bad
lighting:
brightness: 80Use only true and false, in lowercase. Values like yes, no, on, and off look friendly, but they confuse people who are new to YAML. YAML 1.2 also dropped them as booleans, so sticking to true and false keeps examples future proof.
# Good
enabled: true
visible: false
# Bad
enabled: True
visible: off
debug: yesComments help the reader understand what an example does.
- Put the comment on its own line, above the line it explains. Comments at the end of a line get hard to read on small screens.
- Indent the comment at the same level as the line it belongs to.
- Put a space after the
#, and start the comment with a capital letter.
# Good
sensor:
# Check every five minutes
scan_interval: 300
# Acceptable, but prefer the style above
sensor:
scan_interval: 300 # Check every five minutes
# Bad
sensor:
# Check every five minutes
scan_interval: 300
#Check every five minutes
timeout: 10
# check every five minutes
retries: 3YAML calls them sequences. In the documentation, call them lists.
Write lists in block style, with each item indented under its key.
# Good
colors:
- red
- green
- blue
# Bad
colors:
- red
- green
- blueAvoid flow style, the inline form with square brackets. It looks compact, but it gets hard to read once the values grow. If you do use it, put a space after each comma, and no spaces just inside the brackets.
# Acceptable
colors: [red, green, blue]
# Bad
colors: [ red, green, blue ]
colors: [red,green,blue]
lights: ["light.living_room_window", "light.living_room_corner"]Mappings are also known as dictionaries, hash tables, or key/value pairs. In the documentation, call them mappings.
Always write mappings in block style. Flow style, which looks like JSON, is not allowed.
# Good
position:
x: 10
y: 20
# Bad
position: { x: 10, y: 20 }Leave a null value empty. Do not write null or ~.
# Good
history:
# Bad
history: null
history: ~Quote strings with double quotes. Some values in Home Assistant examples are an exception, see Strings that stay unquoted.
# Good
greeting: "Welcome home!"
# Avoid
greeting: Welcome home!
# Bad
greeting: 'Welcome home!'Do not use \n to add line breaks, and do not write long strings on a single line. Use a block scalar instead:
- The literal style,
|, keeps the line breaks you write. - The folded style,
>, joins the lines into one, with a space between them.
# Good
message: |
The washing machine is done.
Time to empty it.
summary: >
This text is spread over several lines in YAML,
but Home Assistant reads it as one single line.
# Bad
message: "The washing machine is done.\nTime to empty it.\n"Prefer | and > without a chomping indicator. If an example needs different handling of the line breaks at the end, you can use:
- The strip indicator,
|-or>-, to remove the final line break and any empty lines after it. - The keep indicator,
|+or>+, to keep the final line break and any empty lines after it.
Home Assistant often accepts the same configuration in more than one form. These rules pick one, so all examples look alike.
Do not include an option that is set to its default value. The exception is an example that is specifically about that option.
The same goes for empty sections, like conditions: [] or data: {}, and for mode: single, which is the default mode of automations and scripts.
# Good
triggers:
- trigger: state
entity_id: binary_sensor.front_door
actions:
- action: light.turn_on
target:
entity_id: light.hallway
# Bad
mode: single
triggers:
- trigger: state
entity_id: binary_sensor.front_door
conditions: []
actions:
- action: light.turn_on
target:
entity_id: light.hallway
data: {}When the reader has to fill in a value, write the placeholder in capitals, with underscores between words. That makes it obvious what to replace.
api_key: YOUR_API_KEY
host: YOUR_DEVICE_IP_ADDRESSWrite examples so they work in the configuration.yaml file, unless the text clearly says otherwise.
Strings get double quotes, with one exception. The following values are easier to read without quotes, so leave them unquoted:
- Entity IDs, like
binary_sensor.front_door - Entity attributes, like
temperature - Device IDs
- Area IDs
- Platform types, like
lightorswitch - Trigger types, like
stateortime - Condition types, like
stateornumeric_state - Action names, like
light.turn_on - Device classes, like
motionorproblem - Event names
- Values that only accept a fixed set of options, like
modein automations
# Good
actions:
- action: notify.mobile_app_phone
data:
message: "The front door is open."
- action: light.turn_on
target:
entity_id: light.hallway
area_id: entrance
data:
transition: 5
# Bad
actions:
- action: "notify.mobile_app_phone"
data:
message: The front door is open.You can point an action at an entity in three places: under target, directly on the action, or inside data. Always use target.
It is the most flexible option. Besides entities, a target can hold devices, areas, floors, and labels, and you can combine them.
# Good
actions:
# Target one entity
- action: light.turn_on
target:
entity_id: light.living_room
# Target every light in an area
- action: light.turn_on
target:
area_id: living_room
# Combine an area, an entity, and a device
- action: light.turn_on
target:
area_id: living_room
entity_id: light.office_desk
device_id: 8f2b6e4c1a9d4e7b9c3f5a1d2e6b8c4f
# Bad
actions:
- action: light.turn_on
entity_id: light.living_room
- action: light.turn_on
data:
entity_id: light.living_roomMany options accept either one value or a list of values. Some also accept a comma-separated string. For those options:
- Use a single value when there is only one. Do not wrap it in a list.
- Use a block style list when there is more than one.
- Never put several values in one comma-separated string.
# Good
entity_id: light.living_room
# Good
entity_id:
- light.living_room
- light.kitchen
# Bad
entity_id: light.living_room, light.kitchen
# Bad
entity_id: [light.living_room, light.kitchen]
# Bad
entity_id:
- light.living_roomOptions like triggers, conditions, actions, and sequence accept either one mapping or a list of mappings. Always use a list, even when there is only one item.
A list shows the reader they can add more items. It also lets them copy one item into their own configuration without changing its shape.
# Good
actions:
- action: light.turn_on
target:
entity_id: light.living_room
# Bad
actions:
action: light.turn_on
target:
entity_id: light.living_roomTemplates are powerful, but they are hard to read for people who are new to them. If plain YAML can do the job, use that instead.
There is a second reason. On home-assistant.io, templates need extra escaping, so the site does not mistake them for Liquid. See Liquid helpers. No template, no escaping.
# Good
conditions:
- condition: numeric_state
entity_id: sun.sun
attribute: elevation
below: 4
# Bad
conditions:
- condition: template
value_template: "{{ state_attr('sun.sun', 'elevation') < 4 }}"A template is a string, so it gets double quotes. Use single quotes inside the template.
# Good
greeting: "{{ 'Good morning' if now().hour < 12 else 'Hello' }}"
# Bad
greeting: '{{ "Good morning" if now().hour < 12 else "Hello" }}'Split a long template over multiple lines, so the reader can follow the logic. Use a block scalar for this, as described in Long strings.
# Good
conditions:
- >-
{{
is_state('lock.front', 'locked')
and is_state('lock.back', 'locked')
}}
# Bad
conditions:
- "{{ is_state('lock.front', 'locked') and is_state('lock.back', 'locked') }}"The bad example is still short. Picture it with five more conditions, and you see why it does not scale.
For template conditions, use the shorthand. It is shorter and cleaner.
# Good
conditions: "{{ states('sensor.outdoor_temperature') | float(0) > 25 }}"
# Bad
conditions:
- condition: template
value_template: >-
{{ states('sensor.outdoor_temperature') | float(0) > 25 }}Put a space on both sides of the filter pipe, |. If that makes the expression unclear, add parentheses.
# Good
conditions:
- "{{ states('sensor.humidity') | float(0) > 60 }}"
- "{{ target == (states('input_number.target') | int(0)) }}"
# Bad
conditions:
- "{{ states('sensor.humidity')|float(0) > 60 }}"
- "{{ target == (states('input_number.target')|int(0)) }}"Use the helper functions to read states and attributes: states(), is_state(), state_attr(), and is_state_attr(). Do not read them from the states object directly.
The helpers handle entities that are not ready yet, like during Home Assistant startup. Reading the states object directly gives errors in that case.
# Good
temperature: "{{ states('sensor.temperature') }}"
target: "{{ state_attr('climate.living_room', 'temperature') }}"
# Bad
temperature: "{{ states.sensor.temperature.state }}"
target: "{{ states.climate.living_room.attributes.temperature }}"