bonjour: Zeroconf/mDNS Service Discovery
The `bonjour` package provides a pure JavaScript implementation of the Bonjour (also known as Zeroconf or mDNS/DNS-SD) protocol for Node.js environments. It allows applications to publish services on the local network, making them discoverable by other Bonjour-compatible devices, and to discover services advertised by others. The library is currently at version 3.5.1 and has an infrequent, as-needed release cadence. Its key differentiator is its full implementation in JavaScript, relying on the `multicast-dns` package for the underlying DNS operations. Unlike some alternatives, it offers both service advertisement and discovery capabilities within a single, lightweight API, making it suitable for local network peer-to-peer communication without central servers.
Common errors
-
Error: bind EADDRINUSE 0.0.0.0:5353
cause Another process on the system is already using UDP port 5353, which is the standard mDNS port `bonjour` attempts to bind to.fixEnsure no other Bonjour/mDNS service (or another instance of your application) is running. On some systems, restarting the machine can resolve this. You can also pass custom `port` options to the `multicast-dns` server when initializing `bonjour` if necessary, though this might hinder interoperability. -
Service not found or 'up' event never fires.
cause This typically indicates a network issue (firewall, router blocking multicast, client/server on different subnets) or an incorrect service `type` being searched for versus what is being published.fixDouble-check that both the publishing and browsing applications are on the same local network segment and are using identical service `type` strings. Temporarily disable firewalls for testing. Use network debugging tools (like Wireshark) to inspect mDNS traffic on port 5353. -
TypeError: bonjour is not a function
cause This error occurs when `require('bonjour')` or `import bonjour from 'bonjour'` is not immediately invoked as a function to create the instance.fixUse `const bonjour = require('bonjour')();` for CommonJS or `import bonjourFactory from 'bonjour'; const bonjour = bonjourFactory();` for ESM to correctly initialize the Bonjour instance.
Warnings
- gotcha The `bonjour` factory function (`require('bonjour')()` or `bonjourFactory()`) creates an instance. It is crucial to call `bonjour.destroy()` when the application exits or the Bonjour functionality is no longer needed, to properly close the underlying UDP socket and stop broadcasting, preventing resource leaks.
- gotcha Bonjour relies on UDP multicast, which can be affected by network configurations, firewalls, and VPNs. Services might not be discoverable across different subnets or through restrictive network policies.
- gotcha Service advertisements might not be immediately visible, and discovery can take a few seconds as it relies on multicast DNS broadcasts. Conversely, 'down' events for services are not always instantaneous, as a device might disappear without sending a 'goodbye' message.
- deprecated While `bonjour` is still active, an official rewrite in TypeScript named `bonjour-service` is available. For new projects, especially those using TypeScript, `bonjour-service` might be a more modern and actively developed alternative with better RFC compliance.
Install
-
npm install bonjour -
yarn add bonjour -
pnpm add bonjour
Imports
- bonjourFactory
import { bonjour } from 'bonjour'; // Incorrect named import const bonjour = new bonjour(); // Not a classimport bonjourFactory from 'bonjour'; const bonjour = bonjourFactory();
- bonjourInstance
const bonjour = require('bonjour'); // Missing function call const { publish } = require('bonjour'); // No named exports for methodsconst bonjour = require('bonjour')(); - Service
import { Service } from 'bonjour'; // Not directly exportedconst service = bonjour.publish(...);
Quickstart
import bonjourFactory from 'bonjour';
const bonjour = bonjourFactory();
// Advertise an HTTP server on port 3000
const service = bonjour.publish({
name: 'My Bonjour Web Server',
type: 'http',
port: 3000,
txt: { version: '1.0', path: '/' }
});
service.on('up', () => {
console.log('Service published:', service.name, service.host, service.port);
});
// Browse for all http services
const browser = bonjour.find({ type: 'http' });
browser.on('up', (foundService) => {
console.log('Found an HTTP server:', foundService.name, foundService.host, foundService.port);
});
// Stop browsing after 10 seconds and destroy all services/connections
setTimeout(() => {
console.log('Stopping discovery and unpublishing service...');
browser.stop();
bonjour.unpublishAll(() => {
console.log('All services unpublished.');
bonjour.destroy(); // Close the UDP socket
console.log('Bonjour instance destroyed.');
});
}, 10000);
// Handle process exit to ensure cleanup
process.on('SIGINT', () => {
console.log('Received SIGINT. Destroying Bonjour instance...');
bonjour.destroy();
process.exit();
});