Main

Putting Home Assistant Configuration Under Git: What to Commit, What to Keep in secrets.yaml, and How to Diff a Broken Automation

Version control for a Home Assistant configuration is not a backup strategy. It is a review tool. The two get conflated constantly, and the conflation is why people either skip Git entirely or commit a folder full of tokens and database files. The useful split is narrower: commit the YAML you actually maintain by hand, keep credentials in secrets.yaml and out of the repository, and use git diff to read what changed before you reload anything. A known-good commit plus an off-device backup is the restore path; Git alone is not.

Why the config directory is worth versioning at all

On Home Assistant OS, the main configuration.yaml lives in the /config folder of the installation, and the path is visible under Settings > System > Repairs > three-dots menu > System information. On Container installs it is the config folder you mounted into the container. That is the directory worth putting under Git, with exclusions.

The reason is not nostalgia for text files. It is that a broken automation is almost always a small, specific edit: a renamed entity, a trigger that lost its to:, a condition that now evaluates false because a template changed. Without a diff you are reading the whole file and guessing. With a diff you are reading three lines and checking them against the documented automation schema.

Home Assistant does not publish a version-control policy. The documentation describes where files live and how secrets are handled; it does not tell you to run git init. Treat the practice as an operational recommendation, not an official one.

What to commit

Commit the files you edit by hand and would want to review line by line:

  • configuration.yaml and any split YAML files it includes.
  • Hand-written automation YAML, including labeled automation blocks and separate automation files you maintain yourself.
  • ESPHome device YAML, Zigbee2MQTT and Z-Wave JS configuration files that live outside the Home Assistant config directory but belong to the same system — in their own repositories if you prefer, but versioned somewhere.
  • Scripts, templates, and custom integration configuration that you would otherwise reconstruct from memory.

One file needs a different treatment: automations.yaml. The Home Assistant documentation states that the UI writes automations to automations.yaml, that the file is managed by the UI, and that it should not be edited manually. Committing it is fine and useful — a diff of a UI-created automation still shows you what changed — but do not treat the committed copy as the source of truth and hand-edit it. If you want hand-maintained automations, put them in a separate YAML file and include that file from configuration.yaml.

What to leave out: the database, logs, .storage (it contains auth and registry state), backups, and anything generated at runtime. A .gitignore that excludes those directories keeps the repository small and keeps you from committing state that will conflict on every restart.

What belongs in secrets.yaml

The configuration file is plain text and readable by anyone with file access, and it can contain passwords and API tokens that need redaction before sharing. The documented mechanism is !secret: create secrets.yaml in the configuration directory, replace the inline value with a !secret identifier, and put the value in secrets.yaml under that identifier. The documentation’s example replaces an inline REST password with password: !secret rest_password and stores rest_password in secrets.yaml.

Two details matter for a Git workflow:

Resolution order. Secrets are resolved by searching the same folder as the YAML file that references them, then parent folders, stopping at the folder containing the main configuration.yaml. If you split configuration into subfolders, a secrets.yaml in a subfolder can shadow the top-level one. Keep one secrets.yaml at the top level unless you have a reason not to, and add secrets.yaml to .gitignore before the first commit.

No include line. A recurring confusion is whether configuration.yaml needs a secrets: !include secrets.yaml line. It does not. In a Home Assistant documentation issue, a user reported that adding secret: !include secrets.yaml produced Integration error: secret - Integration 'secret' not found, and a maintainer pointed back to the secrets documentation rather than endorsing the include. I have not found an official statement that secrets.yaml is auto-loaded in every current version, so the safe reading is: reference secrets with !secret, do not add an include line, and if a secret fails to resolve, check the resolution order above before changing anything else.

The automations limitation

Using secrets is not supported in the Home Assistant UI YAML editor for automations and scripts. If !secret appears in automations.yaml or scripts.yaml, you will not be able to edit or view any YAML automations or scripts in the UI. The documented workaround is to split secret-bearing automations into a separate YAML file included from configuration.yaml; those automations are read-only in the frontend while the rest stay editable.

There is a second caveat that matters more for a shared repository: secrets used in automations are exposed to administrators when viewed in the UI, including the YAML source viewer and the trace viewer. So !secret keeps the value out of the committed file, but it does not hide it from anyone with admin access to the running instance. If the repository is shared with people who should not see a token, the token should not be in an automation at all.

Diffing a broken automation

Suppose a motion automation stopped firing after a commit. The diagnostic path is short if the repository is clean.

Step 1: see what is uncommitted. git diff with no arguments shows changes in the working tree relative to the index — the differences you have not yet staged. If you edited the file and have not committed, this is the first place to look.

Step 2: see what is staged. git diff --cached shows staged changes relative to a named commit, defaulting to HEAD. If you staged the edit and then noticed the automation was broken, this is the diff that isolates it.

Step 3: compare two commits. git diff <commit> <commit> shows changes between two arbitrary commits. If the automation worked last Tuesday and does not work now, diff the commit from Tuesday against HEAD and read only the hunks that touch the automation file.

Step 4: read the hunk against the schema. The automation documentation lists the current keys: triggers, conditions, and actions at the automation level, with singular trigger: and condition: inside those lists and singular action: for an action call. Older examples use platform: for triggers (renamed in 2024.10) and service: for actions (renamed in 2024.8); Home Assistant still accepts the old keys, but an automation cannot have both trigger: and triggers: in the same place. A diff that shows one form replacing the other is a candidate for the breakage.

Step 5: validate, then reload narrowly. A configuration check is applied automatically when you reload the configuration or restart Home Assistant, and you can run it explicitly from the command line on OS installs. If only automations changed, reload automations rather than restarting the whole system. The documentation is explicit about the cost: reloading stops a running automation, and any for at least duration in progress is lost. That is a real tradeoff on a presence or HVAC automation, and it is a reason to reload during a quiet window rather than the moment you notice the problem.

Graceful degradation: the restore path Git does not give you

A commit is not a backup. The repository lives on the same device as the configuration, so a failed SD card, a bad pull, or a wiped /config takes both. The documented backup path is Home Assistant’s own backup system, and the OS documentation is blunt about placement: store the backup outside the device where Home Assistant is installed, so you can restore from it if the system fails.

There is a reported failure mode worth knowing before you automate pulls. In a Home Assistant apps issue, a user reported that installing the git pull add-on with an empty repository erased the entire config; the log claimed a backup to /tmp that the reporter could not find, and the reporter restored from a snapshot. That is one report, not a general verdict on the add-on, and I have not verified its current behavior. The operational lesson is narrower and does not depend on the add-on: never point an automated pull at a repository you have not confirmed contains a valid configuration, and keep a tested off-device backup before the first pull.

For a small installation, the honest tradeoff is that Git adds real overhead. If you change one automation twice a year, a dated copy of configuration.yaml in a backup and a note of what changed may serve you better than a repository you never diff. Git earns its place when you are editing YAML regularly, when more than one person touches the configuration, or when you need to answer “what changed since it last worked” without reading the whole file.

A repeatable procedure

  1. Locate the configuration directory (Settings > System > Repairs > System information).
  2. Confirm secrets.yaml is in .gitignore and that no token appears in a tracked file.
  3. Run git status, then git diff for unstaged changes or git diff --cached for staged ones.
  4. Read the hunk against the automation schema: trigger, condition, action, and the plural/singular key forms.
  5. Run a configuration check before reloading.
  6. Reload automations only, not the whole system, and accept that running automations and in-progress for durations will be interrupted.
  7. If the change is wrong, revert to the last known-good commit, then restore from the off-device backup if the working tree itself is damaged.

If you are auditing which of these small systems actually matter before you start versioning them, the audit approach in How to Audit the Small Systems That Quietly Run Your Week is a reasonable place to decide what deserves a repository and what deserves a label on the device.

FAQ

Do I need a secrets: !include secrets.yaml line?

No. Reference values with !secret and keep secrets.yaml in the configuration directory. Adding an include line has been reported to produce an integration error, and the documentation does not instruct you to add one.

Can I commit automations.yaml?

You can commit it, and a diff of it is useful. Do not hand-edit it: the documentation says it is managed by the UI and should not be edited manually. Put hand-maintained automations in a separate file.

Why can’t I use !secret in a UI automation?

Secrets are not supported in the UI YAML editor for automations and scripts. Using !secret in automations.yaml or scripts.yaml prevents you from editing or viewing YAML automations and scripts in the UI. Split secret-bearing automations into a separate file instead.

Is Git a backup?

No. It is a review and rollback tool for text you maintain. Keep a Home Assistant backup stored off the device, and test that you can restore from it.