Content Index
The integration of Node.js in Electron refers to the ability to access all Node.js APIs and modules directly from the rendering process (the frontend, your HTML/JS files). This means you can use features like require('fs') to read and write files or import any other Node.js module from your web page, as if you were in a backend environment.
Previously, we saw a feature of Electron which is the Application Debug (devTools) in Chrome Electron.js.
Why is it important and when to use it?
Being able to use Node.js from the web page is one of the most powerful features of Electron. It allows performing operations that a normal web browser could not do for security reasons, such as:
- Accessing the user's file system.
- Executing system scripts or processes.
- Communicating directly with databases.
- Using native Node.js libraries.
This capability is fundamental for building complex desktop applications that go beyond being simple packaged websites.
Security Warning: Enabling Node.js integration (nodeIntegration: true) is a practice that must be handled with care. If your application loads content from remote websites, a malicious script could use this integration to access the user's file system. For production applications, it is strongly recommended to disable this option and use preload scripts instead.
Method 1: Enabling nodeIntegration (The old approach)
In older versions of Electron, Node.js integration was enabled by default. Now, for security, it comes disabled. To enable it, you need to configure two options in the webPreferences of your BrowserWindow.
nodeIntegration: true: Allows the use ofrequire,process, and other Node.js APIs in the rendering process.contextIsolation: false: Removes the context separation between your web page's JavaScript and Electron's internal JavaScript. Without this option,nodeIntegrationwill not work as expected in recent versions.
Being able to use Node from the web page (and with this, being able to import and use any package) is fundamental to carry out several operations, such as the communication between processes that we will see in the next section; to enable Node integration, we place the following.
Here is a complete example in your main file (usually main.js or index.js):
const { app, BrowserWindow } = require('electron');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Enable Node.js integration
nodeIntegration: true,
// Disable context isolation
contextIsolation: false
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
With this configuration, in your index.html file (or the JavaScript you load from it), you could do something like this:
// renderer.js
const fs = require('fs');
const os = require('os');
console.log(`This is the home directory: ${os.homedir()}`);
// Careful! This could be dangerous if the content is dynamic.
fs.writeFileSync('hello.txt', 'Hello from Electron!');
Method 2: Using Preload Scripts - The modern and secure approach
The recommended and most secure way to connect your frontend with Node.js capabilities is through a preload script. This script runs in an environment that has access to both the browser's window and Node.js APIs, but keeps contexts isolated (contextIsolation: true).
The preload script acts as a bridge, selectively and securely exposing the functionalities that your frontend needs.
[Image diagram showing the Context Bridge acting as a secure tunnel between the Renderer Process and the Main Process]
Step 1: Configure the BrowserWindow to use a preload
In your main.js, keep contextIsolation at its default value (true) and specify the path to your preload script.
// main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// Default value is true, but it is good to be explicit
contextIsolation: true,
// nodeIntegration remains false (default value)
// Specify the preload script
preload: path.join(__dirname, 'preload.js')
}
});
win.loadFile('index.html');
}
app.whenReady().then(createWindow);Step 2: Create the preload.js script
This script will expose a secure API to the rendering process through the contextBridge object.
// preload.js
const { contextBridge, ipcRenderer } = require('electron');
const fs = require('fs');
// Securely expose a 'readFile' method to the rendering process
contextBridge.exposeInMainWorld('myAPI', {
readFile: (filePath, callback) => {
fs.readFile(filePath, 'utf-8', (err, data) => {
callback(err, data);
});
},
// You can also expose variables, not just functions
platform: process.platform
});Step 3: Use the exposed API in the frontend
Now, in your frontend's JavaScript, you cannot use require, but you can access the API you have exposed in the window object.
// renderer.js
// myAPI was exposed by the preload script in window
console.log(`We are running on the platform: ${window.myAPI.platform}`);
// Call the secure function to read a file
window.myAPI.readFile('./package.json', (err, data) => {
if (err) {
console.error("There was an error reading the file:", err);
return;
}
console.log("package.json content:", data);
});This second method, although it requires a bit more configuration, is much more secure and is the recommended practice for all modern Electron applications.
The next step is to learn how to create Multi-platform Menus in Electron js.