Building a desktop app with Electron and Create React App (2024)

TL;DR: A step-by-step tutorial explaining how to create a desktop application using Create React App (CRA) and Electron. You can find the source code of the project on GitHub.

I recently needed to wrap a React app generated with Create React App (CRA) with Electron (well, the app itself uses React Native for Web, but it doesn’t matter).
My goal was to stay within the Create React App limits as much as possible (without ejecting).
There’s no shortage of guides on how to do it online. Still, I couldn’t find one that fully follows the Electron security guidelines and provides a distribution setup using Electron-builder.
So, here’s yet another tutorial on how to wrap an app built with Create React App in Electron — from the initial scaffolding up to the distribution workflow.

React app scaffolding

Let’s start from an “empty” React app generated with Create React App.

# Using npx ( to run create-react-app.npx create-react-app my-electron-app

Then, add the following dependencies (most of them are here only to simplify the development flow):

cd my-electron-appyarn add -D concurrently cross-env electron electron-builder electronmon wait-on
  • concurrently: Run multiple commands concurrently. We’ll use it to run both the Electron process and the React app in watch mode.
  • cross-env: Run scripts that set and use environment variables across different platforms. We’ll use it to make our scripts compatible with both Unix and Windows OSes.
  • electron: The core framework for creating the app.
  • electron-builder: A complete solution to package and build a ready for distribution Electron app for macOS, Windows, and Linux.
  • electronmon: Like nodemon, but for the Electron process. Allows watching and reloading our Electron app.
  • wait-on: Utility to wait for files, ports, sockets, etc. We’ll use it to wait for the React app to be built before we open the Electron app (while developing).

Electron’s main script

The next step is creating Electron’s main script. This script controls the main process, which runs in a full Node.js environment and is responsible for managing your app’s lifecycle, displaying native interfaces, performing privileged operations, and managing renderer processes.

Electron’s main script is often named main.js and stored in <project-root>/electron/main.js, but in our case, we’ll name it electron.js (to disambiguate it) and store it in <project-root>/public/electron.js (so that Create React App will automatically copy it in the build directory).


// Module to control the application lifecycle and the native browser window.const { app, BrowserWindow, protocol } = require("electron");const path = require("path");const url = require("url");// Create the native browser window.function createWindow() { const mainWindow = new BrowserWindow({ width: 800, height: 600, // Set the path of an additional "preload" script that can be used to // communicate between node-land and browser-land. webPreferences: { preload: path.join(__dirname, "preload.js"), }, }); // In production, set the initial browser path to the local bundle generated // by the Create React App build process. // In development, set it to localhost to allow live/hot-reloading. const appURL = app.isPackaged ? url.format({ pathname: path.join(__dirname, "index.html"), protocol: "file:", slashes: true, }) : "http://localhost:3000"; mainWindow.loadURL(appURL); // Automatically open Chrome's DevTools in development mode. if (!app.isPackaged) { mainWindow.webContents.openDevTools(); }}// Setup a local proxy to adjust the paths of requested files when loading// them from the local production bundle (e.g.: local fonts, etc...).function setupLocalFilesNormalizerProxy() { protocol.registerHttpProtocol( "file", (request, callback) => { const url = request.url.substr(8); callback({ path: path.normalize(`${__dirname}/${url}`) }); }, (error) => { if (error) console.error("Failed to register protocol"); } );}// This method will be called when Electron has finished its initialization and// is ready to create the browser windows.// Some APIs can only be used after this event => { createWindow(); setupLocalFilesNormalizerProxy(); app.on("activate", function () { // On macOS it's common to re-create a window in the app when the // dock icon is clicked and there are no other windows open. if (BrowserWindow.getAllWindows().length === 0) { createWindow(); } });});// Quit when all windows are closed, except on macOS.// There, it's common for applications and their menu bar to stay active until// the user quits explicitly with Cmd +"window-all-closed", function () { if (process.platform !== "darwin") { app.quit(); }});// If your app has no need to navigate or only needs to navigate to known pages,// it is a good idea to limit navigation outright to that known scope,// disallowing any other kinds of navigation.const allowedNavigationDestinations = "";app.on("web-contents-created", (event, contents) => { contents.on("will-navigate", (event, navigationUrl) => { const parsedUrl = new URL(navigationUrl); if (!allowedNavigationDestinations.includes(parsedUrl.origin)) { event.preventDefault(); } });});// In this file you can include the rest of your app's specific main process// code. You can also put them in separate files and require them here.

Yeah, this is not a “minimal” electron.js setup, but I wanted some nice defaults and made sure we’re following Electron’s security guidelines.

During execution, Electron will look for this script in the main field of the app’s package.json config, so let’s update it:


 {  "name": "my-electron-app",  "version": "0.1.0",  "private": true,+ "main": "./public/electron.js",  "dependencies": {

Electron’s preload script

By default, the process running in your browser won’t be able to communicate with the Node.js process. Electron solves this problem by allowing the use of a preload script: a script that runs before the renderer process is loaded and has access to both renderer globals (e.g., window and document) and a Node.js environment.

In our electron.js script, we already specified that we expect a preload script to be loaded from <project-root>/public/preload.js. So, let’s create it:


// All of the Node.js APIs are available in the preload process.// It has the same sandbox as a Chrome extension.const { contextBridge } = require("electron");// As an example, here we use the exposeInMainWorld API to expose the browsers// and node versions to the main window.// They'll be accessible at "window.versions".process.once("loaded", () => { contextBridge.exposeInMainWorld("versions", process.versions);});

The above code accesses the Node.js process.versions object and exposes it in the React app, making it accessible at window.versions.

Making Create React App compatible with Electron

Our goal is to stay within the Create React App ecosystem without ejecting and use Electron only to render the React app.
To do so, a few tweaks are needed.

Update the homepage property

We need to enforce Create React App to infer a relative root path in the generated HTML file. This is a requirement because we’re not going to serve the HTML file; it will be loaded directly by Electron.To do so, we can set the homepage property of the package.json to ./ (see Building For Relative Paths in the Create React App documentation for more details).


 {  "name": "my-electron-app",  "version": "0.1.0",  "private": true,+ "homepage": "./",  "main": "./public/electron.js",  "dependencies": {

Update browserslist’s targets

Update the browserslist section of package.json to support only the latest Electron version. This ensures Webpack/Babel will only add the polyfills and features we strictly need, keeping the bundle size to the minimum.


 "browserslist": {  "production": [+ "last 1 electron version",- ">0.2%",- "not dead",- "not op_mini all"  ],  "development": [+ "last 1 electron version",- "last 1 chrome version",- "last 1 firefox version",- "last 1 safari version"  ]  },

Define a Content Security Policy

A Content Security Policy (CSP) is an additional layer of protection against cross-site scripting attacks and data injection attacks. So I highly recommend to enable it in <project-root>/public/index.html.
The following CSP will allow Electron to run only inline scripts (the ones injected in the HTML file by Create React App’s build process).


  <meta name="theme-color" content="#000000" />  <meta  name="description"  content="Web site created using create-react-app"  />+ <meta+ http-equiv="Content-Security-Policy"+ content="script-src 'self' 'unsafe-inline';"+ />

Please keep in mind this is just a minimal CSP example. You can tweak it further to allow-list only specific websites, and you can make it even stricter by generating a nonce to load only the inline scripts you generated in the build process. See Content Security Policy (CSP) on MDN Web Docs for more info.

Define the start/development script

In your package.json, define a script to build the Create React App and start the Electron process in watch mode:


  "scripts": {  "start": "react-scripts start",  "build": "react-scripts build",  "test": "react-scripts test",  "eject": "react-scripts eject",+ "electron:start": "concurrently -k \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electronmon .\""  },

Here’s a breakdown of what it does:

  • concurrently -k invokes the subsequent commands in parallel, and kill both of them when the process is stopped.
  • cross-env BROWSER=none yarn start sets the BROWSER=none environment variables (using cross-env for Windows compatibility) to disable the automatic opening of the browser and invokes the start script, which runs the Create React App build in watch-mode.
  • wait-on http://localhost:3000 && electronmon . waits for the Create React App dev-server to serve the app on localhost:3000, and then invokes electronmon . to start the Electron add in watch-mode.

You can now run yarn electron:start to run your React app within Electron instead of the browser window.

Package the the Electron app for distribution

Finally, we need to make a few minor changes to the Create React App setup to generate platform-specific distributables so that our app can be installed.We’ll use Electron-builder, a configuration-based solution to package and build ready for distribution Electron apps for macOS, Windows, and Linux.

Electron-builder offers a ton of configuration options, but for the sake of simplicity in this guide we’ll add just the bare minimum settings to create working distributable files.

Set the app author and description

Electron-builder infers a few default info required to bundle the distributable file (app name, author, and description) from the package.json, so let’s specify them:


  "name": "my-electron-app",  "version": "0.1.0",  "private": true,+ "author": "John Doe",+ "description": "My fantastic Electron app",  "homepage": "./",  "main": "./public/electron.js",  "dependencies": {

Set the build configuration

Let’s add a minimal Electron-builder configuration in the package.json using the build key on top level:


+ "build": {+ "appId": "com.electron.myapp",+ "productName": "My Electron App",+ "files": ["build/**/*", "node_modules/**/*"],+ "directories": {+ "buildResources": "public"+ },+ "mac": {+ "target": "dmg"+ },+ "win": {+ "target": "nsis"+ },+ "linux": {+ "target": "deb"+ }+ }
  • appId: The application ID used to identify the app in the macOS (as CFBundleIdentifier) and Windows (as App User Model ID).
  • productName: The name of the app, as shown in the app executable.
  • directories.buildResources: Path of the root dir that holds resources not packed into the app.
  • files: Global of additional files (outside of directories.buildResources) required by the app to run.
  • mac, win, linux: Platform-specific configurations.

Add an app icon

By default, Electron-builder will look for an app icon in <root-project>/build/icon.png — so you should be good to go as long as you put it in the public directory (Create React App build process will take care of moving it to the build directory).

For more info, see the Electron-builder icons documentation.

Add the packaging scripts

Finally, to make Electron-builder package our app we can add a packaging script for each destination platform in the package.json:


  "scripts": {  "start": "react-scripts start",  "build": "react-scripts build",  "test": "react-scripts test",  "eject": "react-scripts eject",  "electron:start": "concurrently -k \"cross-env BROWSER=none yarn start\" \"wait-on http://localhost:3000 && electronmon .\"",+ "electron:package:mac": "yarn build && electron-builder -m -c.extraMetadata.main=build/electron.js",+ "electron:package:win": "yarn build && electron-builder -w -c.extraMetadata.main=build/electron.js",+ "electron:package:linux": "yarn build && electron-builder -l -c.extraMetadata.main=build/electron.js"  },

These commands will build a React app production bundle and package it into distributables for Windows, macOS, and Linux respectively. By default, the distributables will be in NSIS (Windows), dmg (macOS), and deb (Linux) form.

The generated distributable files will be place in <project-root>/dist, so make sure to add this directory to .gitignore:

 # production /build+/dist


That’s it.
You can now run yarn electron:start to kickstart your development flow, and yarn electron:package:<platform> to generate a distributable bundle.

Please keep in mind that the project created with this tutorial represents what I consider the bare minimum to requirements to wrap a React app with Electron. I highly recommend taking some time to read the Electron and Electron-builder official documentation to tweak your setup.

You can find the complete code for this blog post on GitHub.

Building a desktop app with Electron and Create React App (2024)


Can I build a desktop app with React? ›

You can create a Windows desktop app using React Native for Windows by following these steps. Open a command line window (terminal) and navigate to the directory where you want to create your Windows desktop app project.

How to build desktop app using electron? ›

Build a Simple Electron. js Project
  1. Create a web page for the application home screen.
  2. Load the application home screen when the Electron. js app is booted up.
  3. Load the home screen when the app's icon is clicked if the app's windows are closed but the app is still running.
Nov 13, 2020

Does electron support React? ›

Electron is a cross-platform desktop application framework. It is used to build desktop applications with the JavaScript language. It's definitely also possible to use JavaScript frameworks like React and Vue to build desktop applications with Electron.

Is React overkill for small apps? ›

Using React can be overkill if the requirements are too simplistic. For example, you need to make a few pages with no dynamic elements or customization. In cases like these, it might suffice to use simple HTML and a bit of JavaScript.

Is React Native better than electron? ›

React Native Windows offers more development languages than Electron, which means that you don't need much prior knowledge. When implementing an app using React Native Windows the main focus and the majority of code will be in JavaScript.

Is Electron for desktop apps? ›

Electron is a software development framework, that is based on JavaScript and is designed for developing cross-platform desktop applications.

Can an Electron app run on web? ›

Since Electron runs on Chromium, it provides you with a browser window for a new or existing web application. Basically, it's flexible enough to where you can still use your favorite front-end libraries (React, Angular, Vue, etc.) to create awesome web interfaces.

Can you make web apps with Electron? ›

This launched me into a path of web development. Electron is an open-source framework created by Github that can be used to build cross platform desktop applications with JavaScript, HTML, and CSS. It has been used to develop applications such as Atom, Visual Studio Code & Tidal.

Is Spotify desktop made with Electron? ›

Conversation. Spotify is an Electron app meaning that it's just Chrome running a fancy website pretending to be an app.

Can Electron apps run without Internet? ›

Electron is the framework being used for a native application. A standalone desktop app just means that you can download the application to your desktop and open it up whenever without Internet!

Is Vscode an Electron app? ›

Electron is the main framework that enables VS Code for desktop to run on all our supported platforms (Windows, macOS, and Linux). It combines Chromium with browser APIs, the V8 JavaScript engine, and Node. js APIs, as well as platform integration APIs to build cross platform desktop applications.

Does Electron need backend? ›

Electron will act as a wrapper for the existing web app without requiring any changes to the backend. Setting up Electron is easy for this type of app!

How do I convert React web app to desktop app? ›

Use CLI flags --mac , --win , --linux to specify platforms. And --ia32 , --x64 to specify arch. And . dmg file to install in macOS or going to mac folder and running directly.
Let's get started
  1. Some differences when releasing in desktop mode. ...
  2. Install necessary packages and config the package.json file. ...
  3. Config Electron.

Does Electron have backend? ›

Electron is one of the most popular desktop frameworks today. Electron uses HTML, JavaScript, and CSS for its front end and Node. js for its backend. This design enables developers to quickly write and easily maintain cross-platform applications between their desktop and web applications.

When should I not use React? ›

When you are making an app like a game or a demanding creative app, React is not the best choice. This problem stems from the fact that it uses a Virtual DOM. Virtual DOMs, or VDOMs, are layers that help make unoptimized DOM manipulations faster.

Is React obsolete? ›

Yes, React class components will fade away in the future. If you want to embrace modern React, then you should use function components with hooks. That's why you will find most tutorials out there teaching modern React and no class components anymore.

Is React going to obsolete? ›

Is React Native dying? React Native is not going to go away any time soon. JavaScript has been around since 1995 and it gives no signs of retiring any time soon — it was the most popular programming language on Stack Overflow's yearly survey for the past few years.

Is Electron a PWA? ›

If your device has a PWA-compatible browser, you can access the PWA at any time, even when you are not connected to the internet. Electron-based programs, on the other hand, are a hybrid form of desktop applications that are uninstallable on mobile devices.

Is React harder than React Native? ›

However, ReactJS does not natively support mobile devices, so you will need to use a third-party toolkit like React Native or Cordova to create mobile apps with ReactJS. On the other hand, React Native is a mobile-specific framework that can create cross-platform apps. It is more difficult to set up than ReactJS.

Why use React Native instead of React? ›

The primary benefit of using React Native is that it allows developers to build cross-platform apps. With code reusability, you can use one codebase to deploy on both Android and iOS platforms.

Is Electron good for desktop development? ›

This means that for a web or NodeJs developer, Electron offers an amazing developer experience and makes desktop apps a practical business decision for companies. Even big companies with tons of talent and cash still choose Electron because it makes more business sense at the end of the day.

Is Electron good for desktop? ›

With an improved runtime and great integration with JavaScript and Node. js, Electron JS makes both designing desktop apps and maintaining them on cross platforms easier and better.

What database should I use for Electron app? ›

RxDB is a NoSQL database for JavaScript applications. It has manny features that come in handy when RxDB is used with UI based applications like you Electron app. For example it is able to subscribe to query results of single fields of document.

Are Electron apps heavy? ›

Large storage footprint: Shipping with a full Chromium runtime, you can expect most Electron apps to consume at least 150 MB of storage. Slow: Some Electron apps are definitely slow, but that can depend on many factors.

Are Electron apps slow? ›

It is slow

It is just the renderer, and just like a web app in a regular browser, it uses HTML, CSS and JavaScript to build an interface and provide functionality. Those are a lot of extra layers. And because of this additional abstraction, it can be slower than a finely tuned native app.

What language is Electron written in? ›


Can we use bootstrap in Electron app? ›

The User Interface of Electron apps is built using HTML, CSS and JS. So we can leverage all the available tools for front-end web development here as well. You can use the tools such as Angular, Backbone, React, Bootstrap, and Foundation, to build the apps.

Can Electron apps be fast? ›

Electron's number one strength is its turnaround speed. No other application development framework can go from 0 to fully functioning app as quickly as Electron can. Recently we were able to turnaround an app for a client in 2 weeks, because it was built on top of an existing React library.

Is Electron just Chrome? ›

Electron supports a subset of the Chrome Extensions API, primarily to support DevTools extensions and Chromium-internal extensions, but it also happens to support some other extension capabilities.

Is Postman made with Electron? ›

As most people know, Postman is made in Electron. However, it does not run into CORS issues when attempting to make API calls. If a normal user packaged a simple electron app that made API calls using Fetch/XHR however, they will be blocked by endpoints that have a CORS policy.

In what GUI is Spotify built in? ›

The Spotify Desktop client is a Windows and Mac native application that uses CEF (Chromium Embedded Framework) to display a web-based user interface.

Is Telegram desktop made with Electron? ›

Telegram Desktop was programmed with C++ and a handful of others. The Android app was built with Java. Swift was used for the iOS and MacOS native app.

What is the difference between Electron desktop app and web app? ›

PWA (Progressive Web Apps) are web apps that you save from your browser as a “desktop app”. It's still a web app, but you open it as if it were a desktop app. Electron apps are desktop apps developed with web technologies. You install them just like desktop apps, and often the developer also offers a web version.

Why does Electron use so much RAM? ›

Electron will use a ton of memory because it's running a full browser inside a browser/desktop, Chromium, along with running v8 and all of it's own code. Along with that Chromium is already known for high memory usage. So it's relatively normal to see high memory.

Are Electron apps insecure? ›

In the wide world of desktop software development, there are more lightweight solutions. However, the biggest problem with Electron applications is security. It is too easy to create a highly insecure Electron application.

Do Google engineers use VS Code? ›

“Various teams at Google are using Visual Studio Code extensively in a number of projects, including Chrome, Angular and more.

Why is VS Code built with Electron? ›

Robust and extensible architecture. Architecturally, Visual Studio Code combines the best of web, native, and language-specific technologies. Using Electron, VS Code combines web technologies such as JavaScript and Node. js with the speed and flexibility of native apps.

Is VS Code built with React? ›

We do not, and never did, use any web framework, such as React or Vue.

Does Electron require NodeJS? ›

To begin developing an Electron app, you need to install the Node. js runtime and its bundled npm package manager onto your system. We recommend that you use the latest long-term support (LTS) version.

Why do developers use Electron? ›

The reasons why professional Electron JS developers enjoy using it include its low barrier to entry, fast speed of development, automatic updates and convenient installers, cross-platform support, and its large community of developers and users. Wireframe vs Mockup vs Prototype.

Can you build an app with only React? ›

Supports Cross-Platform Application Development: By using React JS, you can make applications for a variety of platforms, including iOS and Android platforms. Therefore, you no longer have to learn different languages, like C++ and Java.

How do I convert React Web app to desktop app? ›

Use CLI flags --mac , --win , --linux to specify platforms. And --ia32 , --x64 to specify arch. And . dmg file to install in macOS or going to mac folder and running directly.
Let's get started
  1. Some differences when releasing in desktop mode. ...
  2. Install necessary packages and config the package.json file. ...
  3. Config Electron.

Does React have a GUI? ›

React Node GUI is an extension of Node GUI that renders the component tree you write into the desktop platform. Features of React Node GUI include: Cross-platform desktop app development, similar to React Native for mobile platform. Styling using CSS with support for flexbox layout.

Can you run React build locally? ›

To test your production build we need to first install http-server package. I have installed the package globally, however, that is optional and can be run locally as well. Navigate to the specified address and you will be able to test your react production build.

Can you create a React app without redux? ›

You don't need Redux for your React app

Now with access to React Hooks and Context API, you might not have to use Redux after all. And when shouldn't you use Redux? As a beginner, you should be trying to think in React, you can apply the idea of Redux without using it at all in a vanilla React app.

Is React only good for single page apps? ›

React is great for single page applications because it allows developers to create applications that are mobile first and responsive. React allows developers to create applications that are fast and easy to update, which is great for mobile applications.

What is better than React? ›

Vue JS. VueJS is one of the fastest-growing alternatives to React and is mainly targeted toward the development of single-page apps and UIs. The open-source JavaScript framework is one of the most flexible, developer-friendly, and fastest alternatives available to developers right now.

How do I turn my React app into PWA? ›

How to Create a Progressive Web App with React? [Step-by-Step]
  1. Step 1: Set up a simple React app. ...
  2. Step 2: Register a Service Worker. ...
  3. Step 3: Configure the Web Application Manifest. ...
  4. Step 4: Test your PWA.
Feb 1, 2023

How do I make a React app executable? ›

  1. Step 1 : Make Sure the Node app is installed and ready to launch. ...
  2. Step 2 : Create a exe file that executes the run command to start the application. ...
  3. Step 3 : Create a setup file to extract the files and create a shortcut on desktop and start menu. ...
  4. Step 4 : Create a installer for systems without nodeJS Pre installed.
Sep 16, 2022

Can I create React app without Internet? ›

first time you need to install the CRAO CLI via this command, then after you'il be able to create React apps offline.

Which UI is best for ReactJS? ›

So here's the list of best UI frameworks for react that can help React Developers build their ReactJS app quickly and effectively.
  • Chakra UI. ...
  • Ant Design for React. ...
  • Material UI. ...
  • Semantic UI react. ...
  • React Admin. ...
  • React Bootstrap. ...
  • React Router. ...
  • React Virtualized.
Feb 3, 2023

What is the best UI for ReactJS? ›

Top 23 React UI Component Libraries for 2023
  1. Material-UI. Material-UI (MUI) is a fully loaded UI component library that offers a comprehensive set of UI tools to create and deploy new features at speed. ...
  2. Ant Design (AntD) ...
  3. React Bootstrap. ...
  4. Chakra UI. ...
  5. Blueprint. ...
  6. visx. ...
  7. Fluent. ...
  8. Semantic UI React.
Nov 3, 2022

Is there an IDE for React? ›

Reactide is one of the few and the first IDEs dedicated to React development only. It's a cross-platform desktop application that offers a custom simulator, making build-tool and server configuration unnecessary.

Top Articles
Latest Posts
Article information

Author: Carmelo Roob

Last Updated:

Views: 6174

Rating: 4.4 / 5 (45 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Carmelo Roob

Birthday: 1995-01-09

Address: Apt. 915 481 Sipes Cliff, New Gonzalobury, CO 80176

Phone: +6773780339780

Job: Sales Executive

Hobby: Gaming, Jogging, Rugby, Video gaming, Handball, Ice skating, Web surfing

Introduction: My name is Carmelo Roob, I am a modern, handsome, delightful, comfortable, attractive, vast, good person who loves writing and wants to share my knowledge and understanding with you.