How Home Assistant Manages Integration Configuration Through Config Entries
Home Assistant stores every integration instance in an immutable ConfigEntry object managed by the core module homeassistant/config_entries.py, which orchestrates setup, state transitions, error recovery, and lifecycle events through an asynchronous state machine.
The home-assistant/core repository uses config entries as the canonical mechanism for managing runtime integration configuration. Unlike static YAML configuration, config entries provide a programmatic, UI-driven way to add, configure, and remove integrations while persisting state across restarts.
The ConfigEntry Data Model
Immutable Configuration Container
At the heart of the system lies the ConfigEntry class defined in homeassistant/config_entries.py (lines 391-410). This dataclass serves as an immutable container holding:
domain: The integration namespace (e.g.,zwave_js,mqtt)title: Human-readable name shown in the UIdata: Static configuration data (API keys, host addresses)options: User-modifiable preferences (polling intervals, enable/disable toggles)runtime_data: Ephemeral objects like API clients or connection sessionsunique_id: Optional identifier preventing duplicate entriesstate: Current lifecycle stage tracked viaConfigEntryState
ConfigEntryState Lifecycle States
The ConfigEntryState enum (config_entries.py#L47-L66) defines discrete stages including LOADED, NOT_LOADED, SETUP_ERROR, and SETUP_RETRY. Each state carries a recoverable flag indicating whether the entry supports unloading and reloading without a full Home Assistant restart.
Registration and Discovery Flows
Handler Registry
Before any integration can be configured, it must register a ConfigFlow subclass in the handlers registry. The core maintains this mapping at homeassistant/config_entries.py (lines 33-35):
HANDLERS: Registry[str, type[ConfigFlow]] = Registry()
Integrations populate this registry using the decorator pattern:
@config_entries.HANDLERS.register("my_integration")
class MyConfigFlow(config_entries.ConfigFlow):
"""Handle config flow for My Integration."""
Discovery and User Flows
Configuration flows originate from either user interaction (SOURCE_USER) or automatic discovery protocols like Bluetooth, DHCP, or Zeroconf. The DiscoveryFlowHandler in homeassistant/helpers/config_entry_flow.py (lines 30-65) provides a generic base class for these automatic flows, setting a unique ID before invoking async_step_confirm to create the entry.
Setup and Migration Sequence
Migration Phase
Before the integration loads, the core validates version compatibility by calling async_migrate (config_entries.py#L521-525). If migration returns False, the entry transitions to MIGRATION_ERROR and setup aborts.
async_setup_entry Execution
The setup orchestration occurs in ConfigEntry._async_start_setup (config_entries.py#L556-L559), which distinguishes between platform setup (entities) and config-entry setup (integration logic). The core then:
- Loads the integration module
- Executes any pending migrations
- Calls the integration's
async_setup_entry(hass, entry)coroutine
The integration must return a boolean result, which the core validates at lines 671-676. A missing or incorrect return type triggers error logging and state transition to SETUP_ERROR.
async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
"""Set up My Integration from a config entry."""
coordinator = MyDataUpdateCoordinator(hass, entry)
await coordinator.async_config_entry_first_refresh()
entry.runtime_data = coordinator
return True
Error Handling and Recovery
Retry Logic with Exponential Back-off
When an integration raises ConfigEntryNotReady (indicating temporary unavailability like a offline device), the core catches the exception at lines 776-814 and schedules a retry with exponential back-off calculated at lines 814-819:
# Back-off calculation example from source
wait_time = min(2 ** (entry._tries - 1), 3600) # Cap at 1 hour
The entry state changes to SETUP_RETRY and automatically attempts setup again after the calculated interval.
Re-authentication Flows
Authentication failures trigger a dedicated recovery path. When ConfigEntryAuthFailed is raised (config_entries.py#L800-803), the core invokes async_start_reauth(hass) to launch the config flow again, allowing users to refresh expired tokens or credentials without removing and re-adding the integration.
Other specific exceptions drive distinct state transitions:
ConfigEntryError→SETUP_ERROR(permanent failure)ConfigEntryAuthFailed→ Re-auth flow triggeredConfigEntryNotReady→SETUP_RETRYwith back-off
Summary
- ConfigEntry objects in
homeassistant/config_entries.pyserve as immutable containers for integration configuration, runtime data, and state. - Lifecycle states (
LOADED,SETUP_RETRY, etc.) managed byConfigEntryStatedetermine whether an integration can recover from failures without restart. - Setup orchestration calls
async_setup_entryafter running migrations, with strict boolean result validation. - Error recovery uses exception-driven state changes:
ConfigEntryNotReadytriggers exponential back-off retries, whileConfigEntryAuthFailedinitiates re-authentication flows. - Discovery integration happens through
DiscoveryFlowHandlerinhelpers/config_entry_flow.py, supporting automated setup via Bluetooth, DHCP, and Zeroconf.
Frequently Asked Questions
What is a config entry in Home Assistant?
A config entry is an immutable runtime object that stores an integration's configuration data, options, and state. Defined in homeassistant/config_entries.py as the ConfigEntry class, it replaces static YAML configuration for many integrations, enabling UI-based setup and management while persisting across Home Assistant restarts.
How does Home Assistant handle integration setup failures?
The core catches specific exceptions during async_setup_entry execution to determine the failure type. ConfigEntryNotReady triggers automatic retries with exponential back-off (config_entries.py#L814-L819), ConfigEntryAuthFailed starts a re-authentication flow (config_entries.py#L800-L803), and generic ConfigEntryError moves the entry to SETUP_ERROR.
What is the difference between async_setup_entry and async_setup?
async_setup is the legacy initialization function for YAML-based configuration, while async_setup_entry is the modern entry point called for each config entry instance. The core in homeassistant/config_entries.py handles the ConfigEntry lifecycle separately from platform setup, allowing multiple independent instances of the same integration with different configurations.
How do discovery flows create config entries?
Discovery handlers inherit from DiscoveryFlowHandler in helpers/config_entry_flow.py, which automatically sets a unique ID based on the discovered device properties and invokes async_step_confirm. Upon user confirmation (or automatically for ignored discoveries), the flow calls async_create_entry, instantiating a ConfigEntry that the core then persists and sets up via async_setup_entry.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →