Skip to content

HMR WebSocket port conflict when running multiple Nuxt apps simultaneously #1170

@productdevbook

Description

@productdevbook

HMR WebSocket port conflict when running multiple Nuxt apps simultaneously

Environment

  • Nuxt: 4.2.2
  • Vite: 7.3.0
  • Node: 22.x
  • OS: macOS

Description

When running multiple Nuxt apps in development mode simultaneously (e.g., in a monorepo), they conflict on the HMR WebSocket port 24678, even when custom vite.server.hmr.port is configured.

Reproduction

  1. Create two Nuxt apps in a monorepo
  2. Configure different ports for each app
  3. Configure custom HMR port for the second app:
// apps/storefront/nuxt.config.ts
export default defineNuxtConfig({
  vite: {
    server: {
      hmr: {
        port: 24680,
        clientPort: 24680,
      },
    },
  },
})
  1. Run both apps simultaneously
  2. Second app fails with: WebSocket server error: Port 24678 is already in use

Root Cause

Two issues cause this:

Issue 1: SSR environment creates WebSocket on default port

In @nuxt/vite-builder, when config.server.hmr.server is set (Nuxt sets this to share HTTP server), the getPort() call is skipped:

if (typeof config.server.hmr !== "object" || !config.server.hmr.server) {
  // getPort() is called here - but this block is SKIPPED when hmr.server is set
}

This means hmr.port is never assigned. Later, Vite's SSR environment (where hmr: false) tries to create a WebSocket and falls back to 24678.

Issue 2: User-defined HMR port is overwritten

When user sets vite.server.hmr.port, Nuxt's DevServerPlugin later sets hmr.server which causes Vite to share the HTTP server instead of using a standalone WebSocket on the user-specified port.

Proposed Fix

// In DevServerPlugin config()
const userHmrPort = nuxt.options.vite?.server?.hmr?.port;
const userClientPort = nuxt.options.vite?.server?.hmr?.clientPort;
if (userHmrPort) {
  config.server = config.server || {};
  // Override hmr config to use standalone WebSocket (don't set hmr.server)
  config.server.hmr = {
    port: userHmrPort,
    clientPort: userClientPort || userHmrPort,
  };
}

// Also: always assign HMR port even when hmr.server is set
const existingHmrPort = typeof config.server.hmr === 'object' ? config.server.hmr.port : undefined;
if (!existingHmrPort) {
  const assignedPort = await getPort({ port: 24678, ... });
  config.server.hmr.port = assignedPort;
}

Related

Workaround

Apply patches to both @nuxt/vite-builder and vite packages (see attached patch files).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions