Bun --hot flag not working with Bun.listen: EADDRINUSE error on hot reload
04:23 13 Jan 2026

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

  1. Run the server with hot reload: bun --hot index.ts
  2. The server starts successfully and listens on port 9100
  3. Make any code change (e.g., change const RECEIPTS_DIR = "receipts"; to const RECEIPTS_DIR = "receipts2";)
  4. 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:

  1. The existing server should be gracefully closed (including all active connections)
  2. The port should be released
  3. 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_DIR variable

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?

bun