Zigbee2MQTT is a Zigbee to MQTT bridge that allows you to use your Zigbee devices without the vendor's bridge or gateway. It bridges events and allows you to control Zigbee devices via MQTT, integrating them with any smart home infrastructure.
- Language: TypeScript 5.9.3 compiled to JavaScript (ES modules with NodeNext resolution)
- Runtime: Node.js (versions 20, 22, or 24)
- Package Manager: pnpm 10.12.1 (strictly enforced via
packageManagerfield) - Core Dependencies:
zigbee-herdsman(6.2.0 - exact version, handles Zigbee adapter communication)zigbee-herdsman-converters(25.42.0 - exact version, device definitions)mqtt(5.14.1 - MQTT client)winston(3.18.3 - logging)
lib/ # TypeScript source code
├── controller.ts # Main controller orchestrating components
├── mqtt.ts # MQTT client management
├── zigbee.ts # Zigbee network management
├── state.ts # State management
├── eventBus.ts # Event-driven communication
├── extension/ # Extension system (plugins)
│ └── extension.ts # Abstract base class
├── model/ # Domain models (Device, Group)
├── util/ # Utility functions
└── types/ # TypeScript type definitions
test/ # Vitest test files with mocks
data/ # Runtime configuration and database
dist/ # Compiled JavaScript output
- Node.js version 20, 22, or 24
- pnpm 10.12.1 (will be auto-installed via corepack if not present)
# Install dependencies (uses pnpm lockfile)
pnpm install --frozen-lockfile
# For development without lockfile restrictions
pnpm install# Full build (TypeScript compilation + hash generation)
pnpm run build
# Build type definitions only
pnpm run build:types# Watch mode - recompile on file changes
pnpm run build:watch
# In another terminal, start Zigbee2MQTT
pnpm start# Run Biome linter and formatter (check only)
pnpm run check
# Auto-fix linting and formatting issues
pnpm run check:w
# The check runs with --error-on-warnings flag
# Configuration: biome.json (4-space indent, 150 line width, no bracket spacing)# Remove build artifacts
pnpm run clean
# Removes: coverage/, dist/, tsconfig.tsbuildinfo# Run all tests once
pnpm test
# Run tests with coverage report
pnpm run test:coverage
# Watch mode - re-run tests on changes
pnpm run test:watch
# Run benchmarks
pnpm run bench- Coverage: 100% code coverage is enforced (configured in
test/vitest.config.mts) - Framework: Vitest 3.1.1 with @vitest/coverage-v8
- Test Files: Located in
test/directory with.test.tsextension - Mocks: Centralized in
test/mocks/directory - Coverage Report: Generated in
coverage/directory (HTML report atcoverage/index.html)
# Run tests matching a pattern
pnpm vitest run -t "test name pattern" --config ./test/vitest.config.mts
# Run specific test file
pnpm vitest run test/controller.test.ts --config ./test/vitest.config.mts
# Focus on one test area in watch mode
pnpm vitest watch -t "Extension" --config ./test/vitest.config.mts- Module System: ES modules with NodeNext resolution
- Target: ESNext
- Strict Mode: Enabled (
noImplicitAny,noImplicitThis) - Decorators: Experimental decorators enabled (used for
@bindfrombind-decorator)
- Node.js built-in modules (with
node:prefix) - Third-party libraries
- Type-only imports from external packages (using
typekeyword) - Internal absolute imports
- Type-only imports from internal modules
Example:
import fs from "node:fs";
import bind from "bind-decorator";
import type {IClientOptions} from "mqtt";
import {connectAsync} from "mqtt";
import type {Zigbee2MQTTAPI} from "./types/api";
import logger from "./util/logger";- Classes: PascalCase (e.g.,
Extension,Device) - Functions/Methods: camelCase (e.g.,
publishEntityState) - Constants: SCREAMING_SNAKE_CASE (e.g.,
CURRENT_VERSION) - Interfaces/Types: PascalCase (e.g.,
MqttPublishOptions) - Files: camelCase for TypeScript (e.g.,
eventBus.ts)
- Async/Await: Always use async/await, explicitly type return as
Promise<Type> - Error Handling: Use
throw new Error("message"), log with winston logger - Event Handlers: Use
@binddecorator to preservethiscontext - Logging: Use
logger.info(),logger.warning(),logger.error(),logger.debug()
- 4-space indentation
- 150 character line width
- No bracket spacing in objects
- Run
pnpm run check:wto auto-format
# Production build
pnpm run build
# Outputs:
# - Compiled JavaScript in dist/
# - Type definitions in dist/types/
# - Includes hash generation for version tracking# Automatically runs before publishing
pnpm run prepack
# Performs: clean + build- Configuration stored in
data/configuration.yaml - Database in
data/database.db - Logs in
data/log/ - External extensions in
data/external_extensions/ - External converters in
data/external_converters/
All features are implemented as extensions that inherit from the abstract Extension base class:
abstract class Extension {
protected zigbee: Zigbee;
protected mqtt: Mqtt;
protected state: State;
protected publishEntityState: PublishEntityState;
protected eventBus: EventBus;
async start(): Promise<void> {} // Initialize extension
async stop(): Promise<void> {} // Cleanup extension
}Key Points:
- Constructor should only assign properties (no side effects)
- Initialization happens in
start()method - Use EventBus for inter-component communication
- Extensions are loaded and managed by the Controller
Components communicate via the strongly-typed EventBus:
// Emit events
this.eventBus.emit('deviceMessage', {device, message});
// Listen to events
this.eventBus.on('deviceMessage', this.onDeviceMessage, this);The Controller instantiates and injects dependencies into all extensions. Follow this pattern when creating new extensions.
- Always create PRs against the
devbranch - The
masterbranch is for production releases only
# Run all checks
pnpm run check
pnpm test
# Ensure 100% code coverage
pnpm run test:coverage
# Build successfully
pnpm run build- All CI checks must pass (linting, tests, build)
- 100% test coverage maintained
- Code follows Biome formatting rules
- Commit messages should be descriptive
- Reference related issues when applicable
The GitHub Actions CI workflow (.github/workflows/ci.yml) runs:
- Biome code quality checks (
pnpm run check) - TypeScript compilation (
pnpm run build) - Full test suite with coverage (
pnpm run test:coverage) - Benchmarks (on dev branch and PRs)
- Docker image builds (on dev branch and tags)
Important: Device support is NOT added to this repository. All device definitions live in zigbee-herdsman-converters.
- Follow the guide at: https://www.zigbee2mqtt.io/advanced/support-new-devices/01_support_new_devices.html
- No changes to zigbee2mqtt codebase are needed for new devices
- Device definitions are automatically picked up from
zigbee-herdsman-converters
For the easiest development experience, set up a bare-metal installation following: https://www.zigbee2mqtt.io/guide/installation/01_linux.html
- Winston logger is initialized in
lib/util/logger.ts - Log levels:
error,warning,info,debug - Logs are written to console and/or file based on configuration
- Use structured logging with context (device names, IEEE addresses)
- Import errors after file moves: Run
pnpm run checkto verify TypeScript and ESLint - Test failures: Check if mocks in
test/mocks/need updates - Build errors: Ensure Node.js version is 20, 22, or 24
- Coverage issues: View HTML report at
coverage/index.htmlto identify uncovered code
- Use
rimrafSyncfor synchronous file operations - Leverage async/await to avoid blocking
- Cache computed values in getters when appropriate
- EventBus provides loose coupling between components
These dependencies use exact versions (no semver ranges) - do not upgrade without thorough testing:
zigbee-herdsman@6.2.0- Critical for Zigbee protocol compatibilityzigbee-herdsman-converters@25.42.0- Device definitions must match herdsman version
Only these Node.js versions are supported:
- Node.js 20.x
- Node.js 22.x
- Node.js 24.x
Using other versions may cause runtime errors or incompatibilities.
This project requires pnpm 10.12.1. The packageManager field in package.json enforces this via Corepack.
Do not use npm or yarn - they will not respect the pnpm-specific configuration.
- Source files in
lib/are compiled todist/ - Type definitions exported from
dist/types/api.d.ts - Source maps are inlined for debugging
- Uses composite project references for faster incremental builds
To load external extensions:
- Place JavaScript files in
data/external_extensions/ - They will be automatically loaded on startup
- No configuration changes needed
- Linting/Formatting: Biome 2.2.5 (replaces ESLint + Prettier)
- Type Checking: TypeScript 5.9.3
- Testing: Vitest 3.1.1
- Coverage: @vitest/coverage-v8
- Main documentation: https://www.zigbee2mqtt.io/
- Contributing guide:
CONTRIBUTING.md - Coding standards:
.github/copilot-instructions.md - Issue tracker: https://github.com/Koenkk/zigbee2mqtt/issues