How Cherry Studio's Local Transfer Service Discovers Devices on the Network
Cherry Studio uses multicast DNS (mDNS) via the bonjour-service library to automatically discover peers on the same LAN without manual IP configuration.
The local transfer feature in cherryhq/cherry-studio enables seamless file and message sharing between instances on the same network. At the heart of this capability lies a multicast DNS (mDNS) discovery mechanism that leverages the Bonjour protocol to locate available peers dynamically.
How Device Discovery Works
When a user initiates a LAN transfer scan, the LocalTransferService in the main Electron process orchestrates the discovery workflow. The service implements a zero-configuration networking approach, meaning devices automatically find each other without requiring static IP addresses or manual configuration.
Initializing the mDNS Client
The service maintains a singleton Bonjour instance through the getBonjour() method. This ensures efficient resource management by reusing the same mDNS client across multiple discovery sessions.
private getBonjour(): Bonjour {
if (!this.bonjour) {
this.bonjour = new Bonjour() // ← creates the mDNS client
}
return this.bonjour
}
Source: src/main/services/LocalTransferService.ts
Browsing for Cherry Studio Services
Once initialized, the service creates a Bonjour browser specifically looking for services of type cherrystudio over the TCP protocol. This filtered search ensures the application only detects relevant peers running Cherry Studio, ignoring other mDNS advertisements on the network.
const browser = this.getBonjour().find({ type: SERVICE_TYPE, protocol: SERVICE_PROTOCOL })
this.browser = browser
this.bindBrowserEvents(browser)
browser.start()
The constants SERVICE_TYPE = 'cherrystudio' and SERVICE_PROTOCOL = 'tcp' are defined at the top of the service file, making the discovery criteria explicit and maintainable.
Source: src/main/services/LocalTransferService.ts & L124-L130
Handling Peer Events
The bindBrowserEvents() method attaches three critical event listeners to the browser instance:
up– Triggered when a new peer announces itself via mDNS. The service constructs a normalizedLocalTransferPeerobject containing the peer's name, host addresses, and port, then stores it in an internal map.down– Fired when a peer disappears from the network (e.g., application closed or network disconnected). The service removes the peer from the active map.error– Captures any discovery errors, logging them for debugging and surfacing issues through the service state.
Source: src/main/services/LocalTransferService.ts
After processing these events, the service broadcasts the updated peer list to the renderer process via the LocalTransfer_ServicesUpdated IPC channel, ensuring the UI always reflects the current network topology.
Implementing LAN Discovery in Your Application
Developers integrating with Cherry Studio's local transfer capabilities can leverage the exposed APIs to initiate scans and handle discovered devices.
Starting a Network Scan
From the renderer process, trigger a discovery scan using the exposed API:
// In a React component or UI handler
await window.api.localTransfer.startScan()
This invokes the LocalTransfer_StartScan IPC channel, which delegates to LocalTransferService.startDiscovery() in the main process.
Listening for Discovered Devices
Subscribe to discovery updates to receive real-time peer information:
const unsubscribe = window.api.localTransfer.onServicesUpdated(state => {
console.log('Discovered LAN peers:', state.services)
})
// When the component unmounts
unsubscribe()
The callback receives a LocalTransferState object containing an array of LocalTransferPeer objects with details including host addresses, ports, and display names.
Connecting to a Peer
Once discovered, initiate a connection to a specific peer:
const peer = discoveredPeers[0] // select target peer
const ack = await window.api.localTransfer.connect({
host: peer.host,
port: peer.port,
token: 'your-auth-token' // optional authentication
})
console.log('Handshake ACK:', ack)
This triggers the LocalTransfer_Connect IPC channel, handled by the LanTransferClientService in the main process.
Stopping the Discovery Process
To conserve resources and network bandwidth, stop the scan when no longer needed:
await window.api.localTransfer.stopScan()
This halts the Bonjour browser and clears the scanning state flag.
Key Source Files and Architecture
Understanding the complete discovery flow requires familiarity with these specific files in the Cherry Studio repository:
| Component | File Path | Purpose |
|---|---|---|
| Core Service | src/main/services/LocalTransferService.ts |
Implements mDNS discovery, Bonjour instance management, peer state tracking, and IPC broadcasting |
| Preload Bridge | src/preload/index.ts |
Exposes localTransfer API methods (startScan, stopScan, onServicesUpdated) to the renderer process |
| UI Integration | src/renderer/src/components/Popups/LanTransferPopup/hook.ts |
Demonstrates React hook patterns for consuming LAN discovery APIs in the UI layer |
| Type Definitions | packages/shared/config/types.ts |
Defines LocalTransferPeer, LocalTransferState, and related TypeScript interfaces |
| IPC Channels | src/shared/IpcChannel.ts |
Enumerates LocalTransfer_StartScan, LocalTransfer_ServicesUpdated, and other channel constants |
These files collectively demonstrate the full stack implementation of zero-configuration networking, from the low-level mDNS browsing in the main process to the high-level React hooks consumed by the user interface.
Summary
Cherry Studio's local transfer service implements zero-configuration device discovery through the following key mechanisms:
- mDNS/Bonjour Protocol: Uses the
bonjour-servicelibrary to handle multicast DNS advertisements without requiring central DNS servers or manual IP configuration. - Service Type Filtering: Specifically searches for
_cherrystudio._tcpservices, ensuring only relevant peers are discovered. - Event-Driven Architecture: Implements
up,down, anderrorevent handlers to maintain real-time awareness of network topology changes. - IPC Integration: Broadcasts discovery results to the renderer process via
LocalTransfer_ServicesUpdated, enabling reactive UI updates. - Resource Management: Maintains a singleton Bonjour instance and provides explicit
stopScanfunctionality to prevent resource leaks.
Frequently Asked Questions
How does Cherry Studio find other devices without knowing their IP addresses?
Cherry Studio uses multicast DNS (mDNS), a zero-configuration networking protocol that allows devices to broadcast their presence on the local network using hostnames rather than static IP addresses. When a scan starts, the application listens for mDNS advertisements on the _cherrystudio._tcp service type, automatically extracting IP addresses and port numbers from the broadcast packets.
What happens when a device goes offline during a LAN transfer session?
The LocalTransferService binds a down event listener to the Bonjour browser instance. When a peer stops advertising its mDNS service—either because the application closed or the network disconnected—the browser fires the down event. The service then removes the peer from its internal map and broadcasts the updated state via IPC, causing the UI to immediately reflect the disconnection.
Can Cherry Studio discover devices across different subnets or VLANs?
Standard mDNS operates on multicast address 224.0.0.251 with TTL (Time To Live) typically set to 255, meaning packets usually do not traverse routers or cross subnet boundaries. Therefore, Cherry Studio's local transfer service generally only discovers peers on the same local network segment. Cross-subnet discovery would require mDNS reflectors or specific network infrastructure configuration outside the application's control.
Is the device discovery process secure against unauthorized network scanning?
The discovery mechanism itself relies on open mDNS broadcasts, meaning any device on the network can theoretically see that a Cherry Studio instance is running. However, the actual connection and data transfer require an explicit connect call that can include authentication tokens. As shown in the LocalTransferService implementation, while discovery is passive and broadcast-based, the subsequent TCP connection establishment can enforce authorization checks before exchanging sensitive data.
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 →