How to set up hot reload on Electron
By Flavio Copes
How to set up hot reload in an Electron app, with electron-vite and Vite HMR for new projects or the electron-reloader module for small CommonJS apps.
To set up hot reload in an Electron app today, start with electron-vite. It wires Vite into the main and renderer processes, so you get HMR in the window and a fast restart when the main process changes.
Why does this matter? Without it, the workflow is painful. You change a line of CSS, then you quit the app, then you run electron . again, and you wait for the window to show up. Multiply that by a hundred edits a day.
Prefer electron-vite (Vite HMR)
Scaffold a project:
npm create @quick-start/electron@latest
Or add electron-vite to an existing app and follow their getting started guide. Dev looks like:
npm install -D electron-vite
npx electron-vite dev --watch
Renderer changes hot-reload through Vite. The --watch flag is what rebuilds and restarts the app when a main process or preload file changes. Without it, only the renderer reloads. That matches how Electron projects are usually structured now (ESM, separate main/preload/renderer entries).
On a current Electron release (Electron 44 at the time of writing), this is the path to take for anything non-trivial.
Legacy option: electron-reloader
If you have a tiny CommonJS app and you only want a file watcher, electron-reloader still works. Last publish was 1.2.3 in 2022, so treat it as a minimal fallback, not the default.
Suppose you have this sample Electron application:
index.js
const { app, BrowserWindow } = require('electron')
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: true,
},
})
win.loadFile('index.html')
}
app.whenReady().then(createWindow)
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
Install electron-reloader as a development dependency:
npm install -D electron-reloader
Then add this line to the index.js file:
try {
require('electron-reloader')(module)
} catch (_) {}
Notice the try/catch block. You install the module as a dev dependency, so it does not exist in the packaged app your users run. Without the try/catch, the production build would crash on startup with a “module not found” error.
Also notice we pass module to the function. The module uses it to figure out which file is the entry point of your app, so it knows what to watch.
If your main process is ESM ("type": "module"), require and module are not available, so this package does not fit. Use electron-vite there.
Start the application with electron ., or npm start if you have
"start": "electron .",
in your package.json.
Change the <h1> text in index.html and save. The window updates. Change something in index.js and the whole app restarts.
One pitfall: if nothing reloads, check that you added the require line to the main process file, the one listed in the main field of package.json. Adding it to a renderer script does nothing, because the watcher must run in the main process.
Want me to talk about your product? You can sponsor this site.
Related posts about tools: