Problem
When using bun --hot with Bun.listen(), hot reload fails with an EADDRINUSE error because the previous server instance doesn't close before the new one tries to start.
Environment
- Bun version: (please check with
bun --version) - OS: macOS (darwin 25.2.0)
- Node.js compatibility: Using Bun's native APIs
Code
Here's my index.ts file:
import { mkdir } from "node:fs/promises";
import type { FileSink } from "bun";
const PORT = 9100;
const RECEIPTS_DIR = "receipts";
type SocketData = {
writer: FileSink;
bytesReceived: number;
};
// Ensure receipts directory exists
await mkdir(RECEIPTS_DIR, { recursive: true });
const server = Bun.listen({
hostname: "0.0.0.0",
port: PORT,
socket: {
open(socket) {
console.log("Client connected:", socket.remoteAddress, socket.remotePort);
// Generate timestamped filename
const timestamp = Date.now();
const outputFile = `${RECEIPTS_DIR}/receipt-commands-${timestamp}.bin`;
// Create file writer for this connection
socket.data = {
writer: Bun.file(outputFile).writer(),
bytesReceived: 0,
};
},
data(socket, data) {
console.log("Data received:", data);
// data is Uint8Array
const bytes = new Uint8Array(data);
socket.data.bytesReceived += bytes.length;
try {
// Write binary data
socket.data.writer.write(bytes);
} catch (err) {
console.error("Write error:", err);
}
},
close(socket) {
console.log("Client disconnected");
if (socket.data.bytesReceived === 0) {
console.log("No data received, skipping file write");
socket.data.writer.end();
return;
}
// Flush and close writer
socket.data.writer.end();
console.log(`Saved ${socket.data.bytesReceived} bytes`);
},
error(socket, err) {
console.error("Socket error:", socket.remoteAddress, socket.remotePort);
console.error(err);
},
},
});
console.log(`Bun ESC/POS test printer listening on TCP port ${PORT}`);
Steps to Reproduce
- Run the server with hot reload:
bun --hot index.ts - The server starts successfully and listens on port 9100
- Make any code change (e.g., change
const RECEIPTS_DIR = "receipts";toconst RECEIPTS_DIR = "receipts2";) - Hot reload triggers, but fails with the error below
Error
error: Failed to listen at 0.0.0.0
syscall: "listen",
errno: 48,
address: "0.0.0.0",
port: 9100,
code: "EADDRINUSE"
Expected Behavior
When hot reload is triggered:
- The existing server should be gracefully closed (including all active connections)
- The port should be released
- The new server instance should start successfully with the updated code
Actual Behavior
The hot reload mechanism doesn't properly close the existing Bun.listen() server before attempting to start a new instance, resulting in the port still being in use.
Additional Context
- This is a TCP server for receiving ESC/POS printer commands
- The server needs to handle active connections gracefully during hot reload
- I've tried storing the server reference and calling
server.stop()manually, but this doesn't integrate well with the hot reload mechanism - The same issue occurs with any code change, not just the
RECEIPTS_DIRvariable
Question
Is there a way to make bun --hot work properly with Bun.listen(), or is there a recommended pattern for handling server cleanup during hot reload in Bun?