Homey Apps SDK — Skill Guide
This skill helps you build apps for the Homey smart home platform. A Homey app is a Node.js bundle that runs locally on Homey Pro (or in the cloud on Homey Cloud). Apps add Devices, Flow cards, Widgets, and more to the Homey ecosystem.
Key Concepts
SDK version: Always use SDK v3 ("sdk": 3 in the manifest). SDK v3 is async/await everywhere.
Node.js: As of Homey v12.9.0, all platforms run Node.js 22.
Homey Compose: The build system that splits the monolithic app.json manifest into smaller
*.compose.json files. Never edit /app.json directly — edit the compose files instead.
Three core classes you extend in every app:
Homey.App— exported from/app.js, instantiated once on app startHomey.Driver— exported from/drivers/<id>/driver.js, manages pairing and all device instancesHomey.Device— exported from/drivers/<id>/device.js, represents a single paired device
Homey CLI (npx homey) is the primary development tool:
homey app create— scaffold a new apphomey app run— run & debug live on a Homey (uninstalls on quit)homey app install— install persistently for testinghomey app publish— publish to the Homey App Storehomey app driver create— interactively add a driverhomey app flow create— interactively add a Flow cardhomey app validate— check manifest validity
Project Structure (Homey Compose)
com.example.myapp/
├─ .homeycompose/
│ ├─ app.json # Core manifest properties
│ ├─ capabilities/
│ │ └─ <custom_cap_id>.json # Custom capability definitions
│ ├─ flow/
│ │ ├─ triggers/<id>.json # App-level Flow trigger cards
│ │ ├─ conditions/<id>.json # App-level Flow condition cards
│ │ └─ actions/<id>.json # App-level Flow action cards
│ ├─ discovery/
│ │ └─ <id>.json # LAN discovery strategies (mDNS, SSDP, MAC)
│ └─ locales/
│ └─ en.json # App-level translations
├─ assets/
│ ├─ icon.svg # App icon (SVG)
│ └─ images/
│ ├─ small.png (250x175)
│ ├─ large.png (500x350)
│ └─ xlarge.png (1000x700)
├─ drivers/
│ └─ <driver_id>/
│ ├─ assets/
│ │ ├─ icon.svg # Driver icon
│ │ └─ images/ (small, large, xlarge)
│ ├─ device.js # Device class
│ ├─ driver.js # Driver class
│ ├─ driver.compose.json # Driver manifest
│ ├─ driver.flow.compose.json # Driver-specific Flow cards (optional)
│ └─ driver.settings.compose.json # Device settings (optional)
├─ widgets/
│ └─ <widget_id>/
│ ├─ public/
│ │ └─ index.html # Widget frontend
│ ├─ api.js # Widget API handlers
│ ├─ widget.compose.json # Widget definition
│ ├─ preview-dark.png # Widget preview (dark)
│ └─ preview-light.png # Widget preview (light)
├─ locales/
│ ├─ en.json
│ └─ nl.json
├─ settings/
│ └─ index.html # App settings page (optional)
├─ api.js # App Web API (optional, Pro only)
├─ app.js # App class
├─ env.json # Secret environment variables (gitignored!)
├─ README.txt # App Store long description (plain text, no markdown)
└─ .homeyignore # Files to exclude from publishing
How to Use This Skill
When creating a Homey app, follow this workflow:
- Determine the integration type — Is it a LAN device (Wi-Fi/mDNS/SSDP), cloud API (OAuth2/webhooks), or wireless protocol (Z-Wave, Zigbee, 433MHz, BLE, IR, Matter)?
- Read the relevant reference file from
references/for detailed patterns:references/app-and-manifest.md— App class, manifest, settings, environment, i18n, permissionsreferences/drivers-and-devices.md— Driver/Device classes, pairing, capabilities, settings, discoveryreferences/flow-cards.md— Triggers, conditions, actions, arguments, tokens, device Flow cardsreferences/widgets.md— Dashboard widgets, widget settings, widget APIreferences/wireless-and-cloud.md— Wi-Fi/LAN discovery, OAuth2, webhooks, Z-Wave, Zigbee, BLEreferences/publishing.md— App Store guidelines, icons, images, publishing flow
- Scaffold the project following the Homey Compose structure above
- Write the code using SDK v3 patterns (async/await,
this.homey.*managers) - Validate with
homey app validate --level=publish
Scaffolding a New App
When the user asks to create a new Homey app, generate the full file set. At minimum you need:
/.homeycompose/app.jsonwith id, version, compatibility, sdk, name, description, category, etc./app.jsextendingHomey.App- At least one driver with
driver.js,device.js, anddriver.compose.json /locales/en.jsonfor any translated stringsREADME.txt
The app ID must be in reverse domain notation (e.g., com.example.mydevice). Never use "homey" or
"athom" in the app ID.
Minimal app.js
'use strict';
const Homey = require('homey');
class MyApp extends Homey.App {
async onInit() {
this.log('MyApp has been initialized');
}
}
module.exports = MyApp;
Minimal driver.js
'use strict';
const Homey = require('homey');
class MyDriver extends Homey.Driver {
async onInit() {
this.log('MyDriver has been initialized');
}
async onPairListDevices() {
// Return an array of discovered devices
return [];
}
}
module.exports = MyDriver;
Minimal device.js
'use strict';
const Homey = require('homey');
class MyDevice extends Homey.Device {
async onInit() {
this.log('MyDevice has been initialized');
// Register capability listeners
this.registerCapabilityListener('onoff', async (value) => {
// Handle the on/off command
this.log('onoff changed to', value);
});
}
async onAdded() {
this.log('MyDevice has been added');
}
async onSettings({ oldSettings, newSettings, changedKeys }) {
this.log('MyDevice settings changed');
}
async onDeleted() {
this.log('MyDevice has been deleted');
}
}
module.exports = MyDevice;
Minimal driver.compose.json
{
"name": { "en": "My Device" },
"class": "socket",
"capabilities": ["onoff"],
"platforms": ["local", "cloud"],
"connectivity": ["cloud"],
"pair": [
{
"id": "list_devices",
"template": "list_devices",
"navigation": { "next": "add_devices" }
},
{
"id": "add_devices",
"template": "add_devices"
}
]
}
Critical Rules
- Never edit
/app.jsondirectly — it is generated by Homey Compose from*.compose.jsonfiles. - Never overwrite constructors on App, Driver, or Device — use
onInit()instead. - Use
this.homey.*for timers — callthis.homey.setInterval()/this.homey.setTimeout()instead of the global versions, so timers are auto-cleared on app destroy (critical for Homey Cloud multi-tenancy). - Device
datamust be immutable and unique — use MAC addresses or serial numbers, never IP addresses. Store changing properties in the device store or settings. - Always handle promise rejections — unhandled rejections crash apps on Homey Cloud.
Use
.catch(this.error)for fire-and-forget promises. - Access managers via
this.homey— e.g.,this.homey.flow,this.homey.settings,this.homey.drivers. - App instance from Device/Driver:
this.homey.appgives you the App instance. - Environment variables: defined in
/env.json, accessed asHomey.env.VARIABLE_NAME(uppercase, string values only). - ESM support: Homey supports ES modules. See the ESM guide if using
import/exportsyntax.
Homey Cloud Considerations
When targeting Homey Cloud ("platforms": ["local", "cloud"]):
- No local Wi-Fi (no mDNS/SSDP/MAC discovery)
- No App Web API (
api.js) - No app-to-app communication
- No
homey:manager:apipermission - Must handle multi-tenancy: no global state, use
this.homey.*for timers - Apps run in Docker;
homey app runrequires Docker for cloud testing - Unhandled promise rejections will crash the app
Quick Reference: Common Patterns
Polling a Cloud API
async onInit() {
this.pollInterval = this.homey.setInterval(() => {
this.pollDevice().catch(this.error);
}, 30000);
}
async onUninit() {
this.homey.clearInterval(this.pollInterval);
}
Setting Capability Values (Device → Homey)
await this.setCapabilityValue('measure_temperature', 22.5);
// For custom boolean capabilities, this auto-triggers Flow cards
Listening for Capability Changes (Homey → Device)
this.registerCapabilityListener('target_temperature', async (value, opts) => {
await this.api.setTemperature(value);
});
Firing a Flow Trigger
// In app.js onInit():
const myTrigger = this.homey.flow.getDeviceTriggerCard('my_event');
// Later, from a device:
await this.driver.myTrigger.trigger(this, { token_key: 'value' }, {});
Using Device Discovery (mDNS)
Read references/wireless-and-cloud.md for the full discovery pattern including
onDiscoveryResult, onDiscoveryAvailable, and onDiscoveryAddressChanged.
For detailed documentation on any topic, read the relevant reference file listed above. The official documentation lives at https://apps.developer.homey.app/ and the SDK v3 API reference at https://apps-sdk-v3.developer.homey.app/.