Fixing Vite HMR Connectivity in Docker and WSL2 Environments
Learn how to configure Vite's HMR for Docker and WSL2 to prevent full page reloads and maintain application state during development.
25 Sept 2025, 20:21 UTC

The Problem: Full Page Reloads Instead of Hot Updates
When developing in isolated environments like Docker containers or Windows Subsystem for Linux (WSL2), Vite's Hot Module Replacement (HMR) often fails. Instead of updating a specific component in-place, the browser performs a full page refresh, wiping out your current application state and slowing down the development loop.
This happens because Vite's HMR relies on a WebSocket connection between the browser and the dev server. In containerized or virtualized setups, the browser (running on the host OS) cannot resolve the WebSocket request to the internal network address of the container or VM.
Prerequisites
- A project initialized with Vite 4.x or 5.x.
- A framework-specific plugin installed (e.g.,
@vitejs/plugin-reactor@vitejs/plugin-vue) to handle the HMR boundaries. - Node.js environment installed within the container or WSL2 instance.
Configuring the HMR WebSocket
To resolve connectivity issues, you must explicitly tell the Vite client how to connect back to the server from the host machine. This is done via the server.hmr configuration in vite.config.js.
Example Configuration for Docker/WSL2
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
host: '0.0.0.0', // Listen on all addresses, including Docker bridge
port: 5173,
hmr: {
// Force the client to connect to the host machine's IP/localhost
host: 'localhost',
clientPort: 5173,
},
watch: {
// Necessary for some WSL2 setups where file events aren't propagated
usePolling: true,
},
},
});
Configuration Breakdown
| Property | Purpose | Risk/Note |
|---|---|---|
server.host |
Binds the server to 0.0.0.0 so it is reachable outside the container. |
Required for Docker; otherwise, only localhost inside the container is bound. |
server.hmr.host |
Tells the browser which address to use for the WebSocket connection. | Must match the address you use to access the site in your browser. |
server.hmr.clientPort |
Specifies the port for the WebSocket client. | Critical when using a reverse proxy (like Nginx) that maps a different external port to 5173. |
server.watch.usePolling |
Forces Vite to check for file changes manually. | Increases CPU usage; only enable if standard file system events fail. |
Verification and Diagnostics
After applying the configuration and restarting the server, use these steps to verify that HMR is functioning correctly:
- Check the Network Tab: Open Browser DevTools > Network. Filter by
WS(WebSockets). You should see a connection to/@vite/clientwith a status of 101 Switching Protocols. - Monitor the Console: Save a change to a CSS file or a component template. Look for a log entry stating
[vite] hot updated: /src/components/Example.jsx. - Test State Persistence: Type text into an input field in your app. Change a style or a piece of JSX in the code and save. If the text in the input field remains, HMR is working. If the page flashes and the input is cleared, a full reload occurred.
Troubleshooting HMR Failures
Circular Dependencies
If the WebSocket is connected but you still see full reloads, check for circular dependencies. If Module A imports Module B, and Module B imports Module A, Vite cannot determine a safe boundary to update the module. This forces the HMR API to bubble the update up to the root, triggering a full page refresh.
OS File Watcher Limits
On Linux/WSL2, you may hit the inotify limit, preventing Vite from detecting file changes. Run the following command in your terminal to check the current limit:
cat /proc/sys/fs/inotify/max_user_watches
If the number is low (e.g., 8192), you may need to increase it via sysctl to ensure the watcher can track all project files.
Rollback Procedure
If these changes cause the server to fail to start or create security concerns in a shared environment, revert the vite.config.js by removing the server block or commenting out the hmr and watch properties. Restart the dev server to return to default behavior.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.