SuperAPI AI Directory

ha-config-migration

Coding & development

View repository

Updated 10-15 23:48

About this skill

Home Assistant — Config Entry Version Migration

When your config entry schema changes (renaming keys, adding required fields, restructuring data), increment VERSION and implement async_migrate_entry.

Incrementing Versions

# config_flow.py
class MyConfigFlow(ConfigFlow, domain=DOMAIN):
    VERSION = 2        # Increment for breaking schema changes
    MINOR_VERSION = 1  # Increment for non-breaking additions

async_migrate_entry Template

# __init__.py
async def async_migrate_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
    """Migrate old entry to new version."""
    _LOGGER.debug("Migrating from version %s.%s", entry.version, entry.minor_version)

    # Downgrade guard: a major version newer than this code supports means the user
    # rolled HA/the integration back. Fail cleanly — old code cannot read newer-schema
    # data, and falling through to `return True` would load it anyway (silent corruption).
    if entry.version > 2:
        return False

    if entry.version == 1:
        # Migration from v1 to v2
        new_data = {**entry.data}

        # Example: rename a key
        if "old_key" in new_data:
            new_data["new_key"] = new_data.pop("old_key")

        # Example: add new required field with default
        if "new_field" not in new_data:
            new_data["new_field"] = "default_value"

        hass.config_entries.async_update_entry(
            entry, data=new_data, version=2, minor_version=0
        )

    # async_update_entry mutates `entry` in place, so this branch sees version=2 within
    # the same call — the checks run sequentially (a 1->2->2.1 migration cascades).
    if entry.version == 2 and entry.minor_version < 1:
        # Minor version migration (non-breaking additions)
        new_options = {**entry.options}
        new_options.setdefault("new_option", True)

        hass.config_entries.async_update_entry(
            entry, options=new_options, minor_version=1
        )

    _LOGGER.info("Migration to version %s.%s successful", entry.version, entry.minor_version)
    return True

Rules

  • Major VERSION (VERSION = 2): Breaking changes — existing users' data must be transformed
  • MINOR_VERSION (MINOR_VERSION = 1): Non-breaking additions — safe to add defaults
  • Return True on success, False to signal migration failure (entry will be disabled)
  • Guard against downgrades: if entry.version is greater than the latest major VERSION this code supports, return False at the top. A higher-major entry means the user rolled HA/the integration back; old code cannot read the newer schema, so fail the migration cleanly (entry is disabled and surfaced) rather than letting it fall through to return True and load corrupt data silently
  • Always log migration for debuggability
  • Migrate incrementally through versions (1→2→3), not directly to latest

Related Skills

  • Config flow → ha-config-flow
  • Deprecation fixes → ha-deprecation-fixes