Guide · Frontend
Electron 45 Explained (October 2026): Breaking Changes to Fix Before You Upgrade
26 min readUpdated By Saket Bhatnagar
Researched and drafted with AI, reviewed and edited by Saket Bhatnagar.
In short
- Electron 45 is the new stable release of Electron, the framework that runs web code as a desktop app. It shipped on 21 October 2026 with Chromium 156, the browser engine inside every window.
- Your preload script, which runs before your page loads, loses Buffer, setImmediate and the events, timers and url modules. This hits every sandboxed window, and sandboxing has been the default since Electron 20.
- Screen sharing now reaches your permission handler, the main-process function that approves sensitive requests, as "display-capture", not "media". A handler that only allows "media" will block screen sharing.
- The synchronous safeStorage methods for encrypting secrets are deprecated, and Electron 42 no longer gets fixes. Coming from 42 or 43? You also lose 32-bit builds and the old clipboard API.
- Beginners can stop after the upgrade steps. Engineers then get Perfetto trace files, the ASAR file-descriptor trap and the window.open change, with side-by-side 45.0.0 vs 44.9.3 output.
What goes wrong when you bump an Electron app to version 45?
If you are coming from Electron 44, usually nothing goes wrong at build time. The app installs, starts and shows its window, and then a few features fail quietly at runtime. Upgrading to Electron 45 means checking those features by hand, because no compiler will warn you.
Picture a common setup. A billing app for small shops is built with Electron, and the team saves performance traces to find slow screens. Its preload script turns receipts into base64 text with Buffer, a "Share screen with support" button uses screen capture, and the shop's login token is kept with safeStorage. The app is made up, but every failure below is real output we got from Electron 45.0.0 on Linux x64.
After the version bump, three things broke in our test. The preload stopped with "Buffer is not defined", so the receipt button did nothing. Screen sharing failed with "NotAllowedError: Permission denied". The performance trace file would no longer open as JSON.
The safeStorage calls still worked but printed a deprecation warning, which is a deadline rather than a failure. None of these are bugs. They are planned breaking changes listed by the Electron team. This guide walks through each one, shows the fix, and gives you a command or output to check that the fix worked.
Which words do you need before upgrading to Electron 45?
You need six words. Each one gets a plain meaning and an example from the billing app.
- Main process: the one Node.js program that starts your app and opens windows. Example: the billing app's main.js.
- Renderer process: the Chromium web page inside each window. Example: the screen that shows the day's bills.
- Preload script: a small script that runs inside the renderer before the page loads. It exposes a safe set of functions to the page with contextBridge.
- Sandbox: a Chromium security mode that takes Node.js access away from the renderer. Since Electron 20 every renderer is sandboxed unless you set nodeIntegration: true or sandbox: false.
- IPC (inter-process communication): messages sent between the renderer and the main process. Example: the page asks the main process to print a bill.
- Permission handler: a function you set in the main process that answers yes or no when a page asks for the camera, the screen or other sensitive features.
What is new in Electron 45?
Electron 45 moves apps to Chromium 156.0.8078.48, Node.js 24.22.0 and V8 15.6, and adds a handful of new features. It also brings a set of breaking changes, which matter more for an upgrade than the new features do.
We installed [email protected] and printed the versions it really ships. The table compares it with 44.9.3, the newest Electron 44 build on 26 October 2026.
| Part | Electron 44.9.3 | Electron 45.0.0 | What it means for you |
|---|---|---|---|
| Chromium (the browser engine) | 152.0.7977.167 | 156.0.8078.48 | Four Chromium versions of web platform changes arrive at once |
| Node.js (the main-process runtime) | 24.22.0 | 24.22.0 | No Node.js change if you were already on 44.9.3 |
| V8 (the JavaScript engine) | 15.2.124.43 | 15.6.75.19 | New JavaScript engine; native addons need a rebuild for the new Electron |
Only the Windows crash helper below may need a packaging change, so beginners can skim this list. These are the main new features from the official release post:
- Faster startup for sandboxed renderers, because Electron skips its JavaScript bootstrap bundle there, unless the window enables the webview tag.
- Direct ASAR reads. ASAR is the single archive file that packs your app's code. The post says cold reads of large packed files are up to 100x faster, and no temporary files are left behind.
- macOS platform passkeys, the password-free sign-in keys macOS stores for the user, through a new platformPasskeys option on app.configureWebAuthn().
- A Windows Error Reporting helper, electron_wer.dll, so crashReporter, Electron's crash-report collector, can catch more kinds of crashes on Windows 10 20H1 and later. If you rename electron.exe, rename the DLL to match, for example shopbilling_wer.dll, and check that your packager does this.
- Experimental native heap profiling through Perfetto, a tracing tool from the Chromium project. It profiles native memory, not the JavaScript heap.
- An experimental way to connect Chromium's Prompt API to a model your app supplies. A later section explains it.
Which Electron 45 breaking changes affect most apps?
Three changes hit most apps: sandboxed preloads, the screen-capture permission and the safeStorage deprecation. A fourth, the contentTracing file format, matters only if your team saves performance traces. The rest touch narrower features such as files inside ASAR archives and window.open().
| Change | Who is affected | On 44.9.3 | On 45.0.0 | Fix |
|---|---|---|---|---|
| Preload loses Node.js stand-ins | Sandboxed windows (the default) | typeof Buffer is "function" | typeof Buffer is "undefined"; require('url') throws "module not found: url" | Use TextEncoder, btoa, URL, EventTarget, setTimeout |
| Screen capture permission | Apps with setPermissionRequestHandler | Handler sees "media" | Handler sees "display-capture" | Also allow "display-capture", for the right window |
| contentTracing format | Apps that save performance traces | File parses as JSON | Binary Perfetto file, not JSON | Open in the Perfetto UI or convert with traceconv |
| enableHeapProfiling() | Apps that profile native memory | A function | undefined (removed) | Pass nativeHeapProfiling to startRecording() |
| Sync safeStorage | Apps that store secrets | No warning | Deprecation warning on first use | Move to the Async methods before Electron 46 |
Notice the first row's "Who is affected" column. A preload in a window with sandbox: false still had Buffer on 45.0.0 in our run. That is not a reason to turn the sandbox off; it only tells you which windows to check.
All our runs used Linux x64 in a container with Xvfb, a virtual screen. Electron ran as root, so Chromium's OS-level sandbox was switched off with --no-sandbox. The preload sandbox still applied: process.sandboxed was true inside the preload.
Does an Electron 45 change touch your app?
Drag to exploreWalk each question in order. A Yes means that section of this guide applies to your app; notice that only the first question depends on the sandbox setting.
Diagram connections:
- Upgrade to 45.0.0 to Sandboxed preload uses Node?
- Sandboxed preload uses Node? to Swap in Web APIs (Yes)
- Sandboxed preload uses Node? to Custom permission handler? (No)
- Swap in Web APIs to Custom permission handler?
- Custom permission handler? to Allow display-capture (Yes)
- Custom permission handler? to Save traces or secrets? (No)
- Allow display-capture to Save traces or secrets?
- Save traces or secrets? to Perfetto + async safeStorage (Yes)
- Save traces or secrets? to Run the checks (No)
- Perfetto + async safeStorage to Run the checks
- Upgrade to 45.0.0: npm install [email protected] --save-exact
- Sandboxed preload uses Node?: Buffer, setImmediate, events, timers, url
- Swap in Web APIs: TextEncoder, btoa, URL, EventTarget
- Custom permission handler?: setPermissionRequestHandler in main.js
- Allow display-capture: Only for windows that should share
- Save traces or secrets?: contentTracing or safeStorage
- Perfetto + async safeStorage: Update trace tooling and secret code
- Run the checks: Expected output listed in this guide
Why does a sandboxed preload say Buffer is not defined in Electron 45?
Because Electron 45 removed it. In sandboxed preload scripts, the Buffer, setImmediate and clearImmediate globals are gone, and so are the events, timers and url modules. The same applies to service worker preload scripts.
These were never real Node.js code. The breaking-changes page says they were browser polyfills, small stand-ins that Electron bundled into every sandboxed renderer. The sandbox tutorial already listed Buffer and setImmediate as unavailable, so Electron 45 makes the code match the docs.
In a sandboxed preload, require() now loads only electron, electron/renderer and electron/common. The process and global objects stay. ipcRenderer keeps its on(), once() and removeListener() methods, but the static helpers you reached through require('events'), such as events.once(ipcRenderer, ...), are gone.
An everyday picture of the preload
Think of the preload as a bank teller's counter. Customers (your web page) can only pass requests across the counter. The teller (the preload) works inside the booth with a small set of tools, and sends bigger jobs to the back office (the main process) over IPC.
Before Electron 45, the booth had a few borrowed copies of back-office tools, such as Buffer. In 45 those copies were taken away. The teller now uses the standard tools every browser has, or sends the job to the back office.
Where the picture breaks: a real teller can decide to bend the rules. A preload cannot. Whatever your preload exposes through contextBridge, any script running on that page can call.
The replacements, tested on 45.0.0
The billing app's preload below replaces each removed piece with a browser API. We ran it in a default sandboxed window on Electron 45.0.0.
// preload.js for a sandboxed window (the default since Electron 20)
const { contextBridge } = require('electron');
// Was: Buffer.from(text).toString('base64')
function toBase64(text) {
let binary = '';
for (const byte of new TextEncoder().encode(text)) binary += String.fromCharCode(byte);
return btoa(binary);
}
// Was: const { EventEmitter } = require('events')
const cart = new EventTarget();
contextBridge.exposeInMainWorld('shop', {
toBase64,
// Was: require('url').parse(link).host
hostOf: (link) => new URL(link).host,
// Was: setImmediate(fn)
later: (fn) => setTimeout(fn, 0),
onItemAdded: (fn) => cart.addEventListener('item', (e) => fn(e.detail)),
addItem: (name) => cart.dispatchEvent(new CustomEvent('item', { detail: name })),
});From the page, we called each function. window.shop.toBase64('₹250 paid') returned "4oK5MjUwIHBhaWQ=", the same text Buffer.from('₹250 paid').toString('base64') gives in Node.js. hostOf() returned "billing.example.in", and the EventTarget delivered "chai" to the listener.
What just happened? Each removed Node.js helper was swapped for a tool every browser already has. The output did not change: the same base64 text, the same host and the same event.
The TextEncoder step matters for Indian text. The rupee sign ₹ takes three bytes in UTF-8, so "₹10" is five bytes. Calling btoa() straight on a string with ₹ throws an InvalidCharacterError, because btoa() only accepts Latin1 characters, which fit in one byte.
- Buffer: use Uint8Array, TextEncoder and TextDecoder, or atob() and btoa(). You can also bundle the buffer package from npm.
- setImmediate and clearImmediate: use setTimeout(fn, 0) and clearTimeout, or queueMicrotask(fn). They are not exact twins: queueMicrotask runs before any rendering, and setTimeout runs later, so pick by when the work must happen.
- require('url'): URL and URLSearchParams are already global in the renderer.
- require('events'): use EventTarget and CustomEvent, or bundle the events package.
- Anything that needs the file system or other Node.js modules: do it in the main process and ask for it over IPC.
How to check your preload
Search your preload files for the removed names, then run the app and watch the DevTools console of each window. The grep command is in the checks block further down. Run it on the built preload bundle too, because a bundler can pull Buffer or require('events') in from npm packages.
If you missed one, the DevTools console shows "Unable to load preload script" followed by "ReferenceError: Buffer is not defined" (or the name you missed). In our probe on 45.0.0, typeof Buffer printed "undefined" and require('timers') threw "module not found: timers".
Why is screen sharing denied after upgrading to Electron 45?
Because screen, window and tab capture now ask your permission handler for "display-capture" instead of "media". If your handler only says yes to "media", it now says no to screen sharing.
Before 45, a screen capture request arrived as "media" with an empty details.mediaTypes list. Now "media" means only cameras and microphones. A "display-capture" request lists "video", "audio" or both in details.mediaTypes; ours showed ["video"].
This covers getDisplayMedia(), the standard web call for screen capture, and getUserMedia() with the chromeMediaSource and chromeMediaSourceId constraints. If you use setDisplayMediaRequestHandler for getDisplayMedia(), that picker flow is unchanged and still runs after the permission is granted.
One screen-share request in Electron 45
Drag to exploreThe request type is the only thing that changed. Notice the permission name on the second arrow: an allow-list that still says only media now answers No.
Diagram connections:
- Share screen button to Chromium media stack
- Chromium media stack to Permission handler (permission: display-capture)
- Permission handler to display-capture allowed?
- display-capture allowed? to Video track returned (Yes)
- display-capture allowed? to NotAllowedError (No)
- Share screen button: Page calls getUserMedia
- Chromium media stack: Page → Chromium: chromeMediaSource desktop
- Permission handler: Chromium → main process: display-capture
- display-capture allowed?: Main process answers yes or no
- Video track returned: Chromium → page: stream with 1 video track
- NotAllowedError: Chromium → page: Permission denied
The fix is to handle the two permissions separately, and to say yes only where it makes sense. In the billing app, only the support window may share the screen, and only pages loaded from the app's own files get camera or screen access.
// main.js
const { app, BrowserWindow, session } = require('electron');
// Where your own pages load from. Change this to match your app, for example
// 'http://localhost:5173/' for a dev server or 'app://shop/' for a custom protocol.
// One value per build, e.g. app.isPackaged ? 'file://' : 'http://localhost:5173/'
const OUR_PAGES = 'file://';
let supportWin; // the only window allowed to share the screen
app.whenReady().then(() => {
session.defaultSession.setPermissionRequestHandler((webContents, permission, callback, details) => {
const fromOurPages = details.requestingUrl.startsWith(OUR_PAGES);
if (permission === 'media') return callback(fromOurPages); // camera and microphone
if (permission === 'display-capture') { // screen, window or tab
return callback(fromOurPages && webContents === supportWin?.webContents);
}
callback(false);
});
supportWin = new BrowserWindow();
supportWin.loadFile('support.html');
});We ran this handler on 45.0.0 with a second "bills" window open. The support window got a stream with one video track. The bills window got "NotAllowedError: Permission denied", which is what we want.
Set OUR_PAGES to wherever your own pages load from. When we loaded both windows from a local web server but left it as file://, even the support window was refused. Setting it to the server's address brought the support window's stream back.
On 44.9.3, the same handler let both windows share, because the screen request arrived as "media". So the new permission name is also an upgrade: you can finally tell screen sharing apart from the camera.
What about the permission check handler?
Electron also has setPermissionCheckHandler, which answers "is this already allowed?" questions. In our 45.0.0 run, a check handler that allowed only "media" did not block the screen share above. It did make navigator.permissions.query({ name: 'display-capture' }) report "denied".
So the request handler is the one that decides screen sharing on this path. Still search for both handlers, and add "display-capture" to the check handler if pages in your app query permissions before sharing.
How do you switch to the async safeStorage encryption API before Electron 46?
Replace isEncryptionAvailable(), encryptString() and decryptString() with isAsyncEncryptionAvailable(), encryptStringAsync() and decryptStringAsync(). The sync methods still work in 45 but are deprecated, with removal planned for Electron 46.
safeStorage encrypts small secrets, such as a login token, with a key held by the operating system's key store. The breaking-changes page says the async methods use the same per-platform key stores, and data encrypted with encryptString() can be decrypted with decryptStringAsync().
// main.js
const { app, safeStorage } = require('electron');
app.whenReady().then(async () => {
if (process.platform === 'linux' && safeStorage.getSelectedStorageBackend() === 'basic_text') {
console.warn('No OS secret store: safeStorage would use a hardcoded password');
}
if (await safeStorage.isAsyncEncryptionAvailable()) {
const encrypted = await safeStorage.encryptStringAsync('shop-login-token');
const { result, shouldReEncrypt } = await safeStorage.decryptStringAsync(encrypted);
console.log(result, shouldReEncrypt);
}
app.quit(); // demo only: a real app keeps running
});On 45.0.0 this printed shop-login-token false. decryptStringAsync() returns an object, not a string, so read the text from result. The typings say shouldReEncrypt is true when the key has been rotated or a new key offers a different security level. In that case, encrypt the secret again and save the new copy.
The first sync call on 45.0.0 printed this warning: "'safeStorage.isEncryptionAvailable' is deprecated and will be removed. Please use 'safeStorage.isAsyncEncryptionAvailable' instead." Electron 44.9.3 printed nothing for the same call.
One more detail from that run is not documented as of 26 October 2026. The old isEncryptionAvailable() returned false while the async check returned true, on both 44.9.3 and 45.0.0. Do not use the sync result to decide whether the async path works.
What else changes if you are coming from Electron 42 or 43?
You also inherit the breaking changes from Electron 44, and the 45.0.0 release notes list several of them again. The biggest one stops some apps from building at all: there are no more 32-bit builds.
- No 32-bit builds. From v44.0.0, Electron publishes only 64-bit binaries, so Windows x86 (ia32) and Linux 32-bit ARM (armv7l) are gone. The checksum lists show ia32 files for 43.8.3 but none for 44.0.0, 44.9.3 or 45.0.0.
- macOS 13 or later. Electron 44 dropped macOS 12 (Monterey), following Chromium.
- A new clipboard API. The clipboard module is no longer available in the renderer; use navigator.clipboard there. In the main process, read and write methods such as readText() now return Promises, and helpers like readHTML() were removed.
- No openAsHidden. app.setLoginItemSettings() lost the openAsHidden option, which only worked on macOS 12 and older.
- An updated Linux policy. Electron now ships x64 and arm64 Linux binaries and supports major distributions while both Chromium and the distro maker still support them.
- Client certificates. The app's select-client-certificate event now also fires for net module requests and some utility processes, with webContents set to null. Check for null before reading webContents.id.
For the billing app, the 32-bit change is the one to check first. If some shops still run 32-bit Windows, Electron 44 and 45 cannot run there. The breaking-changes page says those platforms lose all support when Electron 43 reaches end of life in January 2027.
Read the 44.0 and 43.0 sections of the breaking-changes page before you jump. The clipboard section alone has a long old-to-new method table.
How do you upgrade an Electron app to version 45 step by step?
Pin the exact version, run two quick checks, then test the changed features on every operating system you ship. Do it on a branch, not on main.
Pin the version
Run npm install [email protected] --save-exact, then move to the newest 45.x release as each one ships. Only the latest release in a line gets fixes.
Confirm what really runs
Run npm ls electron and the version command below. Expect 45.0.0, Chromium 156.0.8078.48 and Node.js 24.22.0.
Rebuild native addons
Any module with compiled C++ code must be rebuilt for the new Electron, for example with the @electron/rebuild tool.
Fix sandboxed preloads
Run the grep check on source and built bundles, rewrite each match with the Web API replacements, and reload every window with DevTools open.
Update the permission handler
Allow "display-capture" only for windows that should share the screen. Click the share button and confirm a video stream starts.
Move secrets to async safeStorage
Swap the sync calls for the async ones, and check the Linux backend is not basic_text.
Check saved traces
If you save traces with contentTracing, open a new one in the Perfetto UI. The tracing section after the stop line has the details.
Check build targets
Coming from 42 or 43, drop ia32 and armv7l targets and port clipboard calls to the Promise API.
Test packaged builds
ASAR changes only show up in a packaged app, so test the installer build, not just npm start.
# 1. Which Electron does the project really run?
npm ls electron
ELECTRON_RUN_AS_NODE=1 npx electron -p "process.versions.electron + ' chrome ' + process.versions.chrome + ' node ' + process.versions.node"
# 2. Which preload lines will break in a sandboxed window?
# Run it on your preload source AND on the built preload bundle.
grep -rnE "\b(Buffer|setImmediate|clearImmediate)\b|require\(\s*['\"](node:)?(events|timers|url)(/[a-z]+)?['\"]\s*\)|from\s+['\"](node:)?(events|timers|url)(/[a-z]+)?['\"]" src/preloadOn our machine the version command printed "45.0.0 chrome 156.0.8078.48 node 24.22.0". ELECTRON_RUN_AS_NODE=1 makes the Electron binary behave like plain Node.js, so no window opens.
The grep pattern assumes your preloads live in src/preload; change the path to match your project. On a test file with GNU grep, it flagged Buffer.from(), require('timers/promises'), require("node:events") and import ... from 'events', and it skipped new ArrayBuffer(8).
What changed in Electron 45's performance tracing and heap profiling?
contentTracing, Electron's built-in performance recorder, now always writes Perfetto protobuf files. The old JSON trace format is gone, and contentTracing.enableHeapProfiling() was removed.
Protobuf is a compact binary format, so you cannot read the file in a text editor or with JSON.parse(). Open it in the Perfetto UI or query it with Trace Processor. Perfetto's traceconv tool can convert it to JSON if an old script needs that.
On 44.9.3, our trace file began with the characters {"tr and parsed as JSON. On 45.0.0, the file began with the bytes 0a 5e 32 55 and did not parse. On 45.0.0, typeof contentTracing.enableHeapProfiling was "undefined".
Heap profiling now goes through the nativeHeapProfiling option of startRecording(). This main.js ran on 45.0.0 and saved a binary trace.
// main.js
const { app, contentTracing } = require('electron');
app.whenReady().then(async () => {
await contentTracing.startRecording({ nativeHeapProfiling: { samplingInterval: 128 * 1024 } });
await new Promise((r) => setTimeout(r, 2000));
const tracePath = await contentTracing.stopRecording();
console.log('trace saved to', tracePath);
app.quit(); // demo only: a real app keeps running
});- samplingRate becomes nativeHeapProfiling.samplingInterval, the average number of bytes allocated between samples. The 45.0.0 typings give Chromium's current default as 131072 bytes (128 KiB).
- The old mode option has no direct equivalent. Every traced process is profiled; to narrow it, use included_process_ids in a TraceConfig.
- The old stackMode option has no equivalent.
Which other Electron 45 changes can break an app quietly?
Several narrower changes can catch apps that use files inside the ASAR archive, window.open(), legacy screen-capture constraints, workers in iframes, Chrome extensions or the storage access API. Check each against your code.
File descriptors for files inside ASAR
fs.open() on a file inside an ASAR archive no longer extracts a temporary copy. The descriptor it returns can be read only through Node.js's fs module. Native addons, child_process stdio, net.Socket({ fd }) and HTTP/2 file responses now fail with EBADF.
We tested this with a small archive holding hello.txt, running the script with ELECTRON_RUN_AS_NODE=1. On 45.0.0, fs.readSync() through the descriptor returned the text, and no temporary file appeared. Passing the same descriptor to a child process as stdin made it fail with "Bad file descriptor". Opening the file for writing failed with EACCES.
On 44.9.3, the child process read the whole file and one new temporary entry appeared. If your app hands ASAR files to other programs, copy the file out first or ship it unpacked.
window.open() between sandboxed and unsandboxed windows
A child window now gets its sandbox state from its own web preferences, and children default to sandboxed. If that differs from the opener's process, the child gets a new process with no opener link.
We opened a child from an unsandboxed window on 45.0.0. window.open() returned null, and the opener's console logged that the child "was created in a separate process without an opener relationship". On 44.9.3, the same call returned a window.
If the opener is unsandboxed and you trust the child's content, set sandbox: false in overrideBrowserWindowOptions.webPreferences inside webContents.setWindowOpenHandler. In our run, that brought the returned window back. The better long-term fix is to sandbox the opener too.
Legacy screen-capture details
- The legacy chromeMediaSource: 'desktop' constraint no longer accepts a WebContents source ID; it fails with an "Invalid state" error. Use chromeMediaSource: 'tab' with an ID from webContents.getMediaSourceId(), or use setDisplayMediaRequestHandler.
- The display-capture Permissions-Policy now also applies to getUserMedia() with chromeMediaSource. A cross-origin iframe needs allow="display-capture" to capture.
- On macOS, the MacCatapLoopbackAudioForScreenShare flag that some apps used to restore screen-share audio no longer has any effect in Electron 45. The breaking-changes page says to add NSAudioCaptureUsageDescription to your app's Info.plist instead (macOS 14.2 and later).
The breaking-changes page says the 'desktop' WebContents rule was also backported to 44.3.0, 43.7.0 and 42.11.3. If you were on a late 44 build, you already have it.
Three smaller ones
- Workers created by iframes get Node.js integration only when the creating frame has it, which for subframes means nodeIntegrationInSubFrames. Backported to 44.3.0, 43.7.0 and 42.11.3.
- Extension pages get window and session preloads only when they are top-level or hosted in DevTools. Also backported to 44.3.0, 43.7.0 and 42.11.3.
- document.requestStorageAccessFor is off by default. The enableBlinkFeatures web preference with RequestStorageAccessFor brings it back for now.
Which Electron versions are still supported after Electron 45?
Electron 43, 44 and 45 are supported as of 26 October 2026. The Electron team supports the latest three stable major versions, so each new major pushes the oldest one out.
| Version | Stable date | End of support | Status on 26 October 2026 |
|---|---|---|---|
| 42 | 5 May 2026 | 20 October 2026 | No longer supported |
| 43 | 29 June 2026 | 5 January 2027 (tentative) | Supported |
| 44 | 24 August 2026 | 2 March 2027 (tentative) | Supported |
| 45 | 20 October 2026 (planned; on npm 21 October) | 27 April 2027 (tentative) | Supported, newest |
| 46 | 5 January 2027 (tentative) | 22 June 2027 (tentative) | Alpha since 23 October 2026 |
Only the latest minor release in each supported line gets fixes, and the oldest supported line gets security fixes only. The last Electron 42 build, 42.11.18, reached npm on 21 October 2026.
For the billing app, staying on 42 means no more Chromium security fixes for a program that opens web content. Counting from 26 October 2026, moving to 44 buys about four months and moving to 45 about six, based on the tentative dates.
What is the experimental Prompt API in Electron 45?
It lets web pages in your app call Chromium's Prompt API, while your app decides which local language model answers. Electron does not ship a model; the app supplies one.
The page calls LanguageModel.create() and then prompt(), as it would in a browser that supports the API. In the main process, you fork a utility process and register it with session.registerLocalAIHandler(). That utility process calls localAIHandler.setPromptAPIHandler() and returns a class built on LanguageModelUtility.
Each window that uses it must set enableBlinkFeatures: 'AIPromptAPI'. The handler receives the webContentsId and securityOrigin, so you can refuse requests from pages you do not trust.
How do you explain an Electron 45 upgrade in a system design interview?
Interviewers rarely ask about one Electron release. They do ask how you would upgrade a framework that bundles a browser engine without breaking users. Electron 45 makes a good worked example.
Name what the framework bundles
Electron ships Chromium, Node.js and V8 inside your app, so every upgrade is also a browser upgrade you are responsible for.
Start from the support window
Only the latest three majors get fixes. That sets how often you must upgrade, not personal preference.
Find runtime-only breaks
Preload globals, permission names and file formats do not fail at build time. Say how you would catch them: grep checks and a smoke test per window.
Keep security boundaries
Fix preloads with Web APIs instead of turning the sandbox off, and grant screen sharing only to the window that needs it.
Roll out in stages
Pin the version, test packaged builds on each OS, ship to a small group through your updater, then widen.
Questions people ask
- When was Electron 45 released?
- Electron 45.0.0 reached npm on 21 October 2026 at 06:03 UTC, which is 11:33 IST, and the official release post is dated 21 October 2026. The release schedule lists 20 October 2026 as the planned stable date. As of 26 October 2026, 45.0.0 carries the latest tag on npm.
- Which Chromium and Node.js versions does Electron 45 use?
- Electron 45.0.0 uses Chromium 156.0.8078.48, Node.js 24.22.0 and V8 15.6. We confirmed this by printing process.versions from the 45.0.0 binary. Late Electron 44 builds, such as 44.9.3, already ship Node.js 24.22.0, so the Chromium and V8 jump is the bigger change for them.
- Do I have to fix my preload if my window uses nodeIntegration: true?
- No, not for this change. Setting nodeIntegration: true or sandbox: false disables the sandbox, and in our test an unsandboxed preload on 45.0.0 still had Buffer and setImmediate. Those settings carry their own security risk, though. Moving to a sandboxed window with Web API replacements is the safer long-term path.
- Will my old safeStorage data still decrypt after I switch to the async methods?
- Yes, according to the Electron breaking-changes page. It says the async methods use the same key stores, and data encrypted with encryptString() can be decrypted with decryptStringAsync(). Remember that decryptStringAsync() returns an object, so read the text from its result property. Test this on each OS you ship before Electron 46 removes the sync methods.
- Can Electron 45 run on 32-bit Windows?
- No. Since v44.0.0, Electron publishes only 64-bit binaries, so there is no Windows ia32 or Linux armv7l build of 44 or 45. Electron 43 still has 32-bit builds, and the breaking-changes page says those platforms lose all support when 43 reaches end of life in January 2027.
- Is Electron 44 still safe to use?
- Yes, for now. Electron 44 is one of the three supported lines as of 26 October 2026, with end of support tentatively on 2 March 2027. Stay on its latest minor release, because only that gets fixes. Plan the move to 45 before that date rather than after it.
- Why can't I open my Electron 45 trace file in the old tool?
- Because contentTracing.stopRecording() now always writes Perfetto protobuf, a binary format, instead of JSON. Older viewers and scripts that read JSON will fail on it. Open the file in the Perfetto UI or Trace Processor, or convert it to JSON with Perfetto's traceconv tool.
Sources and further reading
- Electron 45 release post (Electron blog, 21 October 2026)
- Electron v45.0.0 release notes on GitHub (Breaking Changes list)
- Breaking Changes: 45.0, 44.0 and 43.0 sections (Electron docs)
- Breaking Changes file at the v45.0.0 tag (GitHub)
- Electron README at v45.0.0: platform support
- safeStorage API: Linux backends and basic_text (Electron docs)
- Electron Releases: release schedule with stable and end-of-life dates
- Electron Releases tutorial: support policy (latest three stable majors)
- Process Sandboxing tutorial (Electron docs)
- Local AI Handler tutorial for the Prompt API (Electron docs)