This guide explains how to publish your Home Assistant custom integration to HACS (Home Assistant Community Store), the most popular distribution method for custom integrations.
- Prerequisites
- Repository Structure
- Creating hacs.json
- Version Management
- Submission Process
- Post-Submission
- Common Rejection Reasons
- Maintenance & Updates
Before submitting to HACS, ensure your integration meets these requirements:
- ✅ Minimum Bronze tier quality (see QUALITY_CHECKLIST.md)
- ✅ All tests pass - No failing tests in CI
- ✅ Code quality checks pass - Ruff and mypy with zero errors
- ✅ Proper error handling - No unhandled exceptions
- ✅ Public GitHub repository - Must be publicly accessible
- ✅ Clear README.md - Installation and configuration instructions
- ✅ License file - LICENSE or LICENSE.md (recommend MIT, Apache 2.0, or GPL-3.0)
- ✅ Semantic versioning - Uses MAJOR.MINOR.PATCH format
- ✅ GitHub releases - At least one tagged release
- ✅ Config flow - UI-based setup (no YAML configuration)
- ✅ Unique IDs - All entities have stable unique_id
- ✅ manifest.json version - Must include
"version"field - ✅ No code in repo root - All integration code in
custom_components/your_domain/
Your repository must follow this structure:
your-integration-repo/
├── custom_components/
│ └── your_integration/ # Domain name from manifest.json
│ ├── __init__.py
│ ├── manifest.json # Must include "version" field
│ ├── config_flow.py
│ ├── coordinator.py
│ ├── sensor.py
│ ├── strings.json
│ └── translations/
│ └── en.json
│
├── .github/
│ └── workflows/
│ └── validate.yml # Optional: HACS validation workflow
│
├── README.md # Required
├── LICENSE # Required
├── hacs.json # Required for HACS
└── .gitignore
Important: All integration code must be inside custom_components/your_domain/. HACS will reject repositories with code outside this directory.
Create a hacs.json file in your repository root to configure HACS integration:
{
"name": "Your Integration Name",
"content_in_root": false,
"homeassistant": "2024.4.0"
}{
"name": "Your Integration Name",
"content_in_root": false,
"homeassistant": "2024.4.0",
"country": ["US", "CA", "GB"],
"render_readme": true,
"persistent_directory": "storage",
"iot_class": "local_polling",
"zip_release": false
}| Field | Required | Description |
|---|---|---|
name |
Yes | Display name shown in HACS (can differ from domain) |
content_in_root |
Yes | Always false for integrations (code is in custom_components/) |
homeassistant |
Yes | Minimum Home Assistant version required (e.g., "2024.4.0") |
country |
No | List of country codes where integration is relevant |
render_readme |
No | Set to true to render README.md in HACS UI |
persistent_directory |
No | Directory name for persistent data storage |
iot_class |
No | IoT class from manifest.json (for display) |
zip_release |
No | Set to true if you provide ZIP releases |
Use the oldest Home Assistant version your integration supports:
# Check what HA features you use and when they were introduced
# Common version milestones:
# 2024.4.0 - Python 3.12 minimum
# 2024.11.0 - Python 3.12.3 minimum
# 2025.2.0 - Python 3.13 minimum
# Conservative approach: Test on oldest version you claim to supportTip: Use homeassistant >= MAJOR.MINOR.0 format (patch version 0) unless you need a specific patch.
HACS requires proper version management using semantic versioning.
Format: MAJOR.MINOR.PATCH (e.g., 1.2.3)
- MAJOR - Incompatible API changes, breaking changes
- MINOR - New features, backward-compatible
- PATCH - Bug fixes, backward-compatible
Always update the version in manifest.json before releasing:
{
"domain": "your_integration",
"name": "Your Integration",
"version": "1.2.3",
"...": "..."
}-
Tag your commit with the version number:
git tag -a v1.2.3 -m "Release v1.2.3" git push origin v1.2.3 -
Create GitHub release:
- Go to repository → Releases → "Draft a new release"
- Select tag:
v1.2.3 - Release title:
v1.2.3or descriptive name - Description: Changelog for this version
-
Update CHANGELOG.md (recommended):
## [1.2.3] - 2026-02-07 ### Added - New temperature sensor entity ### Fixed - Connection timeout handling
Tag Format: Use vMAJOR.MINOR.PATCH (e.g., v1.2.3) consistently.
Use the HACS Action to validate your repository:
Create .github/workflows/validate.yml:
name: Validate
on:
push:
pull_request:
workflow_dispatch:
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: HACS Validation
uses: hacs/action@main
with:
category: integrationRun this workflow and fix any validation errors before submitting.
-
Select "Add integration" template
-
Fill out the form:
- Repository URL:
https://github.com/yourusername/your-integration - Domain:
your_integration(from manifest.json) - Brief description
- Confirm all requirements met
- Repository URL:
-
Submit the issue
-
Wait for review (typically 1-7 days)
HACS maintainers will review your submission and may request changes:
- Code quality improvements
- Documentation updates
- Bug fixes
- Validation errors
Respond promptly and make requested changes.
Once approved:
- Your integration appears in HACS
- Users can install via HACS UI
- Automatic update notifications for new releases
After HACS approval, users install via:
- HACS → Integrations → "Explore & Download Repositories"
- Search for "Your Integration Name"
- Click "Download"
- Restart Home Assistant
- Add integration via Settings → Devices & Services
Update your README.md with HACS installation instructions.
HACS provides download statistics:
- Check https://github.com/hacs/integration for metrics
- Monitor issues for user feedback
- Track release downloads on GitHub
Error: "Integration does not have a version in manifest.json"
Fix:
{
"domain": "your_integration",
"version": "1.0.0"
}Error: "Repository has no releases"
Fix:
git tag -a v1.0.0 -m "Initial release"
git push origin v1.0.0
# Create release on GitHub from this tagError: "Integration code must be in custom_components/"
Fix: Move all .py files into custom_components/your_domain/
Error: "Breaking change requires migration path or major version bump"
Fix:
- Implement
async_migrate_entry()in__init__.py - OR bump major version (e.g., 1.x.x → 2.0.0)
- Document migration in release notes
Error: "Security issue found: credentials logged"
Fix: Review SECURITY_BEST_PRACTICES.md and fix:
- Remove credential logging
- Mask sensitive data
- Use proper secret storage
Error: "README.md lacks installation/configuration instructions"
Fix: Add sections:
- Installation via HACS
- Configuration via UI
- Troubleshooting
- Support/contact info
Error: "Integration fails to load in Home Assistant"
Fix:
- Test installation on clean HA instance
- Fix import errors
- Resolve missing dependencies
- Ensure config flow works
- Make changes in your codebase
- Update version in
manifest.json - Update CHANGELOG.md
- Commit changes:
git add . git commit -m "Release v1.2.4: Fix connection timeout"
- Create tag:
git tag -a v1.2.4 -m "Release v1.2.4" git push origin v1.2.4 - Create GitHub release with changelog
HACS users will automatically see update notifications.
If you introduce breaking changes:
Option 1: Provide Migration
async def async_migrate_entry(hass, config_entry):
"""Migrate old entry."""
if config_entry.version == 1:
# Migrate version 1 to version 2
new_data = {**config_entry.data}
new_data["new_field"] = "default_value"
config_entry.version = 2
hass.config_entries.async_update_entry(
config_entry, data=new_data
)
return TrueOption 2: Bump Major Version
- Increment major version (e.g., 1.x.x → 2.0.0)
- Document breaking changes in release notes
- Provide migration instructions for users
When removing features:
- Announce deprecation in version N
- Mark as deprecated with warnings in logs
- Remove feature in version N+1 (minimum 6 months later)
Example:
_LOGGER.warning(
"The 'old_field' configuration is deprecated and will be "
"removed in version 2.0.0. Use 'new_field' instead."
)Use this checklist before submitting:
- Bronze tier quality achieved (see QUALITY_CHECKLIST.md)
- Public GitHub repository
- LICENSE file present
- README.md with installation/configuration instructions
-
manifest.jsonincludes"version"field - At least one GitHub release created
-
hacs.jsoncreated in repository root - Code only in
custom_components/your_domain/ - HACS validation workflow passes (if added)
- Config flow implemented (no YAML setup)
- All entities have unique IDs
- Tests pass in CI
- No security vulnerabilities
- Changelog or release notes provided
- HACS Documentation: https://hacs.xyz/docs/publish/start
- HACS Action: https://github.com/hacs/action
- HACS Default Repository: https://github.com/hacs/default
- Semantic Versioning: https://semver.org/
- GitHub Releases: https://docs.github.com/en/repositories/releasing-projects-on-github
- HACS Discord: https://discord.gg/apgchf8
- Home Assistant Community: https://community.home-assistant.io/
- HACS Issues: https://github.com/hacs/integration/issues
Ready to publish? Follow this guide step-by-step, and your integration will be available to thousands of Home Assistant users through HACS!