Skip to content

Learn to Read YAML Without Memorizing It

11/09/2026
Learn to read YAML without memorizing it

This article may contain affiliate links. If you buy through these links, the price is the same for you and the store pays me a small commission that helps keep Tecnoyfoto running.

← Chapter 1 · Course index

When a YAML configuration fails, it is tempting to move spaces around until Home Assistant stops reporting an error. That may work once, but it does not teach you what was wrong or whether the block still means the same thing. The next change becomes another round of guesswork.

The alternative is not to memorize dozens of rules. It is to learn how spaces, dashes, and colons represent structure. Once you can look at a block and say “this is a list of actions,” “these two lines belong to target,” or “this value is a string, not a boolean,” much of YAML stops looking mysterious.

We will not study every Home Assistant trigger or condition in this chapter. First, we have a more fundamental goal: learning to read the document’s structure. We will use fragments from real automations because that is the kind of YAML you will encounter throughout the course, but our focus will be how those fragments are built.

A simple line: key and value

The easiest unit to recognize is a pair formed by a key and a value:

alias: "Light when opening the door"

The key is alias. The value is Light when opening the door. The colon separates the two parts, and the space after it begins the value.

The key acts as a label for the information being provided, and the value contains that information. YAML knows that the two are related, but it does not know what alias means. Home Assistant interprets that key as the automation’s descriptive name.

We can add more pairs to the same level:

alias: "Light when opening the door"
description: "Turn on the living room light when the door opens"
mode: restart

All three keys begin in the same column. That tells us they are peers: none is nested inside another.

A key may not have the value on the same line

Now look at this fragment:

target:
  entity_id: light.course_living_room

There is no simple value after target:. The next line is indented by two spaces and contains information that belongs to target. Instead of holding a single word, target contains a nested structure.

This is a fundamental idea: a key followed by a colon can open a block. To find where that block ends, examine the indentation of the lines that follow it.

DEALS · OFFICIAL STORE

Discounts on SONOFF smart home

Wi-Fi switches, relays, sensors, LED strips and more. Deals change frequently in the official store.

Coupon: TECNOYFOTO (10% off at checkout)

View official deals Affiliate link Affiliate link · SONOFF store

Indentation shows what belongs where

In ordinary prose, margins and paragraphs make text easier to read. In YAML, leading spaces are not decoration. They show which data is nested inside other data.

actions:
  - action: light.turn_on
    target:
      entity_id: light.course_living_room

We can read the hierarchy from outside to inside:

  1. actions is on the main level.
  2. action and target are part of an element located inside actions.
  3. entity_id is inside target.

If we move entity_id to the left, it ceases to belong to target, even if the words are identical:

actions:
  - action: light.turn_on
    target:
    entity_id: light.course_living_room

This second fragment may still be syntactically valid YAML: target has no value, and entity_id is now at the same level as target. However, it no longer has the structure that a Home Assistant action expects. This is a good example of why a generic YAML validator cannot detect every Home Assistant error.

We will use two spaces per level

Home Assistant follows the convention of indenting two spaces each time we enter a level:

level 0: no spaces
level 1: two spaces
level 2: four spaces
level 3: six spaces

YAML can use other indentation widths when they are applied consistently, but mixing styles makes the document harder to read and easier to break. We will use two spaces throughout this course.

Tabs do not replace spaces

A tab may look like several spaces, but YAML does not allow tabs for indentation. This can be especially misleading because some editors display tabs and spaces almost identically.

If Home Assistant reports a message similar to found character '\t' that cannot start any token, you don’t need to reorganize the entire automation. You need to locate the tab and replace it with spaces. An editor showing invisible characters helps to distinguish them.

Maps: grouping several properties

A map—also called a dictionary—groups key-value pairs. The following target is a map with two properties:

target:
  area_id: living_room
  entity_id: light.course_living_room

area_id and entity_id are aligned. Both belong to target, and neither contains the other.

We can imagine its structure without writing YAML:

target
area_id → living_room
entity_id → light.course_living_room

You do not need to draw this tree every time. The goal is to learn to see it mentally. When a line moves back to the left, the inner block has ended and the document has returned to an outer level.

Keys should not be repeated within the same map

This example tries to define entity_id twice on the same map:

target:
  entity_id: light.course_living_room
  entity_id: light.kitchen

This does not represent two independent targets. It assigns two values to the same key, and one may overwrite the other. To provide multiple entities, you need a list like the one below.

Lists: when you have more than one item

A list contains ordered items. Each item starts with a dash:

entity_id:
  - light.course_living_room
  - light.kitchen

Here, entity_id does not contain one string; it contains a list of two identifiers. Both dashes are aligned because the two values belong to the same level.

Lists can also contain complete maps. This happens all the time in automations:

actions:
  - action: light.turn_on
    target:
      entity_id: light.course_living_room

  - action: switch.turn_on
    target:
      entity_id: switch.course_fan

actions contains two items. Each dash starts a different action. The keys action and target appear inside each item.

The dash does not mean “action,” and it is not specific to Home Assistant. It means “new element of a list” and is part of YAML. Home Assistant, on the other hand, defines which properties each element of the list of actions should contain.

This separation is useful again:

  • The dashes and indentation construct the YAML list.
  • The action, target, and entity_id keys are part of the schema that Home Assistant expects.
  • Values such as light.turn_on or switch.course_fan identify operations and entities of Home Assistant.

Lists and maps are often nested together

An automation is not a “list” or a “map” exclusively. It contains both nested structures.

alias: "Entry lighting"
description: "Turn on the light when the door opens and someone's home."
triggers:
  - trigger: state
    entity_id: binary_sensor.course_front_door
    from: "off"
    to: "on"
conditions:
  - condition: state
    entity_id: binary_sensor.course_someone_home
    state: "on"
actions:
  - action: light.turn_on
    target:
      entity_id: light.course_living_room
  - action: switch.turn_on
    target:
      entity_id: switch.course_fan
mode: restart

We do not yet need to study the behavior of each section. We can describe its form:

  • The main document is a map with the keys alias, description, triggers, conditions, actions, and mode.
  • triggers contains a list. This list has an element, formed by a map with four properties.
  • conditions also contains a list with a map.
  • actions contains a list of two maps.
  • Each action contains a target, and each target contains an entity_id.

If you can read a block this way, you already understand much more than someone who only recognizes isolated words. Even if a particular condition is unfamiliar, you can identify where it starts, which properties belong to it, and where it ends.

Simple values: text, numbers, booleans and nulls

So far, we have focused more on structure than on value types. YAML distinguishes several basic types, and Home Assistant may expect a different type for each option.

Text

These values are text strings:

alias: "Entry lighting"
entity_id: light.course_living_room
to: "on"

An entity identifier contains a period, but it is still a string. The "on" state is also a string, not a command to turn anything on.

Numbers

above: 25
brightness_pct: 60

25 and 60 are interpreted as numbers. They are not quoted because we want to preserve that numeric type.

Booleans

A boolean can only represent true or false:

enabled: true
continue_on_error: false

Here, true and false are not entity states. They are logical values that enable or disable an option.

Why we wrote "on" and "off" in quotation marks

The YAML parser used by Home Assistant can interpret words such as on, off, yes or no as booleans. But the internal state of a light or binary sensor is normally compared as text.

to: "on"

The quotes force on to be kept as a string. Without them, the value could become true, which is not the textual state that the configuration expects. This is one of those small errors that seem arbitrary until you distinguish the type of value.

Null value and empty string

These two lines don’t mean exactly the same thing:

description:
description: ""

The first line leaves the key without a value, which YAML interprets as null. The second contains an empty string. Home Assistant accepts both forms in some places but requires one specific form in others. Do not treat them as interchangeable without knowing what the option expects.

When to use quotation marks

Many simple strings work without quotation marks:

alias: Entry lighting

This is valid YAML, but the Home Assistant style guide prefers double quotes around ordinary text. We will follow that convention for aliases, titles, messages, descriptions, and similar strings. We will leave entity IDs, action names, trigger and condition types, device classes, and fixed values such as mode unquoted, as the guide recommends.

In addition to giving consistency, quotation marks remove ambiguities when the text may be confused with another type or contains special characters.

at: "08:00:00"
to: "on"
message: "Door #1 open: check entry"

In the message, # could start a comment if the string were not quoted. A colon followed by a space also has structural meaning. Quoting the message makes it clear that the entire value is one string.

YAML supports single and double quotes:

message: 'The door is open'
message: "The door is open."

Either style works in basic examples. Double quotes support certain escape sequences, while single quotes treat the contents more literally. We will not mix styles without a reason; we will use whichever form makes the value clearest.

Comments: Explain without changing behavior

The # character starts a comment outside a quoted string:

# This automation uses practice entities
alias: "Entry lighting"
actions:
  - action: light.turn_on  # Turn on the virtual light

Home Assistant ignores the comment. Its purpose is to explain a decision that is not evident when reading the keys.

A useful comment explains the reason:

# Restart the sequence if movement is detected again
mode: restart

A comment that only repeats the line adds little:

# The mode is restart
mode: restart

Nor should we use comments to compensate for incomprehensible names or leave large blocks abandoned for months. A good comment does not simply add more words; it preserves the context needed to understand a decision later.

Multiline text: > and |

Messages and, later, some templates may be too long for a single line. YAML offers two common ways to write them.

The > symbol folds the lines and normally produces a continuous paragraph:

message: >
  The front door is open.
  See if it should stay that way.

The resulting value is one continuous paragraph, with a space between the lines.

The | symbol retains the line breaks:

message: |
  State of the house:
  Open door
  Light on

In both cases, the text must remain indented under message. We will not explore every multiline-block variant yet. For now, recognize that the indented lines form one string value.

The same block may need an outer dash depending on where you paste it

A frequent source of confusion is not the content of an automation, but the place where it is inserted.

The YAML view of an automation editor usually shows your map directly:

alias: "Entry lighting"
triggers: []
conditions: []
actions: []
mode: single

automations.yaml, on the other hand, contains a list of automations. Each automation needs an outer dash:

- id: "course_entrada_iluminada"
  alias: "Entry lighting"
  triggers: []
  conditions: []
  actions: []
  mode: single

And if written directly inside configuration.yaml, then the upper key automation: appears:

automation:
  - alias: "Entry lighting"
    triggers: []
    conditions: []
    actions: []
    mode: single

These are not three interchangeable snippets. They are the same underlying automation placed in three different contexts. Before copying an example, determine whether it represents one automation, an item in a list, or an entire configuration section.

A method for reading any YAML block

When an example feels overwhelming, do not try to understand everything simultaneously.

  1. Which keys are at the top level? Look for lines aligned all the way to the left of the fragment.
  2. What keys open a block? They are the keys that end with a colon and continue with more indented lines.
  3. Where are the lists? Locate the dashes and check which ones are aligned.
  4. What properties belong to each element? Follow the indentation until a line returns to the left.
  5. What type does each value seem to have? Distinguish text, number, boolean, null and multiline blocks.

Only then should you ask what meaning Home Assistant assigns to those keys. Separating YAML structure from Home Assistant behavior greatly reduces the mental load.

Two mistakes that look alike, but are not the same

This fragment has indentation that breaks the YAML structure:

triggers:
  - trigger: state
  entity_id: binary_sensor.course_front_door
    to: "on"

entity_id is not aligned with the other properties of the item started by the dash, and to is placed at a level with no valid parent. The parser cannot construct a coherent structure.

This other fragment can be analyzed as YAML, but entity_id has been left out of target:

actions:
  - action: light.turn_on
    target:
    entity_id: light.course_living_room

In the first case, we expect a YAML syntax or construction error. In the second, the problem appears when Home Assistant validates the action schema. Learning to distinguish these cases prepares you for the diagnostic method we will develop later in the course.

Exercise: reconstruct and repair the structure

The following block aims to turn on two lights when the door opens. It contains several indentation problems and an ambiguous value:

alias: "Turn on the entry lights"
triggers:
  - trigger: state
  entity_id: binary_sensor.course_front_door
  from: off
  to: on
actions:
  - action: light.turn_on
    target:
      entity_id:
      - light.course_living_room
      - light.kitchen
mode: restart

Before correcting, answer:

  1. What keys should belong to the element of triggers?
  2. What value of entity_id is a list?
  3. Which dashes mark items in that list?
  4. What values should be retained as text?
  5. Which keys are at the top level?

Try to correct it without looking at the solution. Then compare structures, not just the visual result.

See the explained solution
alias: "Turn on the entry lights"
triggers:
  - trigger: state
    entity_id: binary_sensor.course_front_door
    from: "off"
    to: "on"
actions:
  - action: light.turn_on
    target:
      entity_id:
        - light.course_living_room
        - light.kitchen
mode: restart

alias, triggers, actions and mode are the main keys.

triggers contains a list. The dash before trigger starts its first item. entity_id, from, and to are properties of the same map, so they are aligned four spaces from the left margin.

The "off" and "on" states are quoted so they remain strings.

actions contains another list. Its first element is a map with action and target. Within target, entity_id contains a list of two values. The dashes of the lights must be a level below entity_id.

If we had merely moved lines until the error disappeared, we could have produced valid YAML with a different meaning. A correct repair begins by deciding which item should contain each property.

What should you take from this chapter?

Spaces in YAML describe relationships. A more deeply indented line belongs to the preceding block; a line that moves back to the left closes one or more levels. Dashes create list items, and aligned keys belong to the same map.

You have also seen that YAML can contain text, numbers, booleans, null values and multiline blocks. Quotes are not an ornament: sometimes they prevent a state like "on" from becoming a boolean.

We have not yet learned how to design an automation. We can, however, inspect its structure and explain where each piece belongs. In the next chapter, we will add the meaning Home Assistant gives those pieces: entities, domains, states, attributes, actions, targets, and data.