
Introduction
React powers a significant portion of the web — according to State of JS 2024, 91% of respondents used React at work. As those web apps mature, teams increasingly ask whether they can ship the same codebase as an installable desktop application — without starting over.
Yes, it's possible — but the result depends heavily on how carefully you handle the conversion.
Electron is the most common path, but wrapping a React app in a desktop shell isn't always plug-and-play. Asset paths break. APIs behave differently outside the browser. Electron installers routinely exceed 100MB for modest apps, and misconfigured IPC or path resolution can silently break features that worked fine in the browser.
This guide covers when conversion makes sense, what to prepare, the exact steps using Electron and Vite, common mistakes to avoid, and when to consider Tauri instead.
TL;DR
- Electron wraps your React app in a native shell bundling Chromium and Node.js, no browser needed
- Asset paths must use relative references, or the app loads a blank screen
- Electron is battle-tested with hundreds of production apps; Tauri is lighter using a Rust backend and the OS's native WebView
- The output is a cross-platform installer (.exe, .dmg, .deb) that works offline
- Best for internal tools, offline-first apps, or anything needing file system access; less suited where binary size matters
When Should You Convert Your React App Into a Desktop App?
Not every React app benefits from a desktop wrapper. The added complexity is worth it in specific circumstances — and actively counterproductive in others.
Strong Use Cases
Convert when your app genuinely needs capabilities the browser can't provide:
- Offline functionality — runs fully without an internet connection, no fallback required
- Local file system access — reads, writes, or manages files directly on the user's machine
- System tray integration — persistent background presence with a tray icon
- OS notifications — native desktop alerts, not browser notification prompts
- Enterprise deployment — ships to machines in a controlled environment (POS systems, inventory dashboards, internal tools)
Real products ship this way. Visual Studio Code, Slack, and Discord are all Electron-based. The Electron Showcase lists over 170 productivity apps and 138 developer tools in production — that's consistent validation the approach scales.
When to Skip or Reconsider
- The app is a lightweight single-purpose utility — Electron's Chromium + Node.js bundle is real overhead for a small tool
- Core functionality depends on live server-side logic or real-time cloud APIs that won't work offline
- You have a hard binary size constraint — if installers must stay small, Electron may not be the right fit (see Tauri below)
- The app has browser-only dependencies that don't translate to a Node.js environment
What You Need Before Getting Started
Skipping this preparation is the fastest path to a frustrating build process. Check these before writing a single line of Electron config.
System and Environment Requirements
- Node.js LTS (v20.x or v22.x recommended — use an LTS line, not the Current release, for stability)
- npm or yarn installed and working
- A React project built with Vite — note that React officially deprecated Create React App in February 2025; Vite is the current standard for new projects
- The project must build successfully via
npm run buildbefore you add Electron — don't try to layer a desktop shell onto a broken build
Project and Code Readiness
Two things will silently break your Electron app if left unchecked:
1. Asset paths must be relative
Electron loads files from the local file system using the file:// protocol. Absolute paths like /assets/logo.png assume a web server root that doesn't exist. Fix this before packaging:
- Vite: Add
base: "./"tovite.config.js - CRA (legacy): Add
"homepage": "."topackage.json
2. Browser-specific APIs need attention
Features that depend on window.location, cookies, or server-side sessions won't work outside a browser context. Audit your codebase for:
- Server-relative URL calls (for example, fetch requests to
/api/...) - Cookie-based authentication
- Any logic that assumes a running web server
These need conditional handling or refactoring before the app will behave correctly as a desktop build.
How to Convert Your React App Into a Desktop App (Step-by-Step)
This guide uses Electron with a Vite-based React project — the standard, well-supported setup as of 2024–2025. Follow these five steps in order.
Step 1: Build Your React App for Production
Run the build command inside your project directory:
npm run build
This generates a dist/ folder containing index.html and all static assets. Confirm the build completes without errors before proceeding — Electron will load this output directly.
Step 2: Install Electron and electron-builder
npm install --save-dev electron electron-builder
Then add these scripts to your package.json:
"scripts": {
"electron": "electron .",
"dist": "electron-builder"
}
electron . launches a local preview window. electron-builder packages the app into platform-specific installers for distribution.
Step 3: Create the Electron Main Process File
Create main.js at the project root. This is Electron's entry point:
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
const win = new BrowserWindow({
width: 1200,
height: 800,
webPreferences: {
nodeIntegration: false,
contextIsolation: true,
preload: path.join(__dirname, 'preload.js') // only if needed
}
});
win.loadFile('dist/index.html');
}
app.whenReady().then(createWindow);
Security defaults to keep in place:
nodeIntegration: false— prevents renderer processes from accessing Node.js APIs directlycontextIsolation: true— isolates preload scripts from the renderer context; default since Electron 12- If your app needs Node.js access, expose it selectively via a preload script — don't disable these settings
Use loadFile() for production static builds. loadURL('http://localhost:3000') only works during active development.
Step 4: Update package.json with Electron Configuration
Set the entry point at the top level:
"main": "main.js"
Then add the electron-builder configuration block:
"build": {
"appId": "com.yourcompany.appname",
"productName": "Your App Name",
"files": ["dist/**/*", "main.js"],
"win": { "target": "nsis" },
"mac": { "target": "dmg" },
"linux": { "target": "AppImage" }
}
electron-builder supports macOS, Windows, and Linux with auto-update out of the box. Default targets are DMG/ZIP for macOS, NSIS for Windows, and AppImage for Linux.
Step 5: Test Locally, Then Build the Installer
Run a local preview first:
npm run electron
Your React app should open in a native window. Verify navigation, static assets, and any data fetching work correctly before packaging.
When ready, build the installer:
npm run dist
This triggers electron-builder and outputs a platform-specific installer to the release/ folder. Always test the installer on the actual target OS — path handling, file permissions, and asset loading can behave differently than the local preview.

Common Mistakes When Converting React Apps to Desktop
These three mistakes account for most failed or broken Electron builds:
1. Pointing Electron at localhost instead of the static build
Using loadURL('http://localhost:3000') only works when your dev server is running. In a packaged installer, nothing is serving that port. Always point to dist/index.html using loadFile().
2. Absolute asset paths
If your built output contains paths like /static/js/main.js, Electron's file:// protocol interprets the leading slash as a drive root, not your project directory. The result is a blank screen with broken assets. Set base: "./" in your Vite config before building.
3. Ignoring package size
Electron bundles Chromium and Node.js — expect your installer to be noticeably large. A few ways to keep it manageable:
- Ensure
asarpackaging is enabled in electron-builder (it's on by default) - Exclude dev dependencies from the packaged output
- Review the
filesarray in your build config — only include what's necessary

If size is a real concern, Tauri is worth evaluating — it's covered in the next section.
Alternatives to Electron for React Desktop Apps
Electron dominates React desktop packaging, but three solid alternatives exist — each suited to different constraints around binary size, integration depth, and deployment overhead.
Tauri
Tauri uses a Rust backend and the OS's built-in WebView instead of bundling Chromium. The result is a much smaller binary — Tauri's documentation states a minimal app can be less than 600KB. A comparable Electron app typically ships between 50–150MB due to the bundled Chromium engine and Node.js runtime.
The trade-offs are real:
- Rust must be installed on the build machine
- The ecosystem is less mature than Electron's
- Rendering can vary slightly across OS WebView versions
Worth it when binary size is a hard constraint.
NW.js
NW.js (formerly node-webkit) is Chromium-based like Electron but uses a different process model — it lets developers call Node.js modules directly from the DOM without a preload bridge. Useful for quick prototypes where that direct access simplifies things. It's less actively maintained than Electron, with a smaller community and fewer build tooling integrations. Choose NW.js only for internal or throwaway prototypes where long-term maintenance isn't a concern.
Progressive Web App (PWA)
If the only goal is installability — not true native integration — a PWA lets users install the React app directly from the browser to their desktop or taskbar. No packaging overhead, no installer.
PWAs do hit a hard ceiling. They depend on browser APIs for file system access (permissioned and browser-dependent), and features like tray icons, auto-updaters, or unrestricted local file access are not available. Choose a PWA when web-first installability is enough; choose Electron or Tauri when you need genuine desktop OS integration.

Frequently Asked Questions
Can React be used to build desktop apps?
Yes. React is a UI library that renders components — the runtime determines the deployment target. Pair it with Electron or Tauri and it runs as a desktop app; the React code itself is largely unchanged.
Is Electron the only way to convert a React app to a desktop app?
No. Tauri is a lighter alternative using Rust and the OS's native WebView. NW.js is another Chromium-based option with a different Node integration model. The right choice depends on bundle size requirements and how much native OS access you need.
Will my existing React code need major changes?
Most UI code works as-is. Three areas typically need attention: asset paths (switch to relative references), browser-specific APIs like cookies or server-relative URLs, and any logic that assumes a live server rather than an offline context.
How large will a React desktop app be when packaged with Electron?
Electron bundles Chromium and Node.js, so installers typically start around 50–80MB. Proper electron-builder configuration — including the files array and asar packaging — helps keep things lean. If size under 10MB is a hard requirement, Tauri is the better fit.
Can a React desktop app built with Electron access native OS features?
Yes. Electron provides APIs for file system access (via Node.js in the main process), OS notifications, system tray integration, shell commands, and auto-update. These are the primary reasons to choose a desktop wrapper over a standard web deployment.
What is the difference between Electron and Tauri?
The core trade-off is ecosystem maturity versus binary size. Electron's larger ecosystem means more community tooling and predictable cross-platform rendering. Tauri's smaller footprint and Rust backend suit projects where distribution size is a priority, though WebView rendering can vary slightly between operating systems.


