Skip to content
All articles

Building an Electron app: a minimal desktop project and release boundaries

Laptop displaying CSS code beside a smartphone
Photo by Negative Space on Pexels

Build an Electron app in 4 stages: create the project, open a local interface, check the desktop lifecycle and prepare a distributable. Electron’s main process controls the application; a renderer displays its web page. The example below creates a fictional collection-desk window. Running it in development and producing an installer are separate outcomes.

Choose Electron when your requirement is a desktop application using web technologies. If customers only need a public information page, a website may avoid a desktop installation altogether. Before writing code, identify the target operating systems, whether any local files are needed and who will maintain installed copies. This tutorial deliberately stops short of customer records, payments and operating-system integrations.

How do you build the first local Electron window?

Start in a new development directory on a machine with Node.js and npm available. Electron’s first-app tutorial uses npm project metadata, an Electron development dependency and a main entry file. Its Windows guidance advises against following this desktop tutorial through WSL. Keep the exercise separate from an existing production project.

These are proposed development commands; they were not executed for this article. Installation downloads dependencies, so review them before running in your own isolated environment:

mkdir collection-desk-demo
cd collection-desk-demo
npm init -y
npm install --save-dev electron
npm pkg set main=main.js
npm pkg set scripts.start="electron ."

Retain the resulting dependency lockfile so later development uses recorded versions. Exclude the installed dependency directory from version control. Do not copy an old version number from a tutorial screenshot and assume it is a supported release; select and maintain an appropriate current version for the implementation.

Create main.js in that directory. This original example follows the documented application-ready and window-lifecycle pattern and makes renderer isolation explicit:

const { app, BrowserWindow } = require('electron');
const path = require('node:path');

function createWindow() {
  const win = new BrowserWindow({
    width: 900,
    height: 650,
    webPreferences: {
      nodeIntegration: false,
      contextIsolation: true,
      sandbox: true
    }
  });
  win.loadFile(path.join(__dirname, 'index.html'));
}

app.whenReady().then(() => {
  createWindow();
  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow();
  });
});

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});

The app object manages lifecycle events; BrowserWindow creates the native window. Creating it after readiness matters because window creation depends on Electron’s initialisation. The activation handler reopens a window when appropriate on macOS, while the final handler follows the usual quit behaviour elsewhere. These are application behaviours worth checking, not decorative boilerplate.

Create index.html beside it. The document has no remote content or inline script. Its security policy restricts resource loading to the application’s own origin:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta http-equiv="Content-Security-Policy"
        content="default-src 'self'; script-src 'self'">
  <title>Collection desk demonstration</title>
</head>
<body>
  <main>
    <h1>Collection desk</h1>
    <p>Fictional reference: SAMPLE-COLLECTION</p>
    <p>No customer records are stored in this demonstration.</p>
  </main>
</body>
</html>

Run npm start in your authorised development environment. The expected result is a desktop window containing the fictional reference. If it fails, first inspect the terminal error, confirm the entry point and check that both files are in the expected directory. Do not solve a blank window by enabling Node integration or disabling web security. This article does not claim that the graphical application was run during authoring.

Keep privileged work outside the page

Electron’s security guidance explains that desktop code can have greater powers than a normal web page. An interface that looks harmless can still sit beside privileged functionality. Keep Node integration disabled for remote content, preserve context isolation and use sandboxing. The explicit settings above make the intended boundary visible; they are not a complete security assessment.

If a later version needs to read a selected file, design a narrow preload interface and validate the corresponding messages. Do not expose a general filesystem or shell command bridge to the renderer. Restrict navigation and new windows when introducing links, and review every dependency added for convenience. The current demonstration needs no such bridge.

How does a working development app become a release candidate?

Electron’s packaging tutorial distinguishes the core runtime from packaging tools. It uses Electron Forge to import an existing project and generate distributables. In an isolated project, after committing or otherwise preserving the working source, its documented route is:

Before importing, open package.json and replace the empty author and description left by npm init -y. Set author to the actual project author and description to an accurate summary, such as “Fictional collection desk demonstration”. Check license against the rights holder’s actual licensing decision: the generated default is not evidence of permission to release the project under that licence. Use the appropriate SPDX identifier or applicable npm licence declaration; do not invent an author or choose a licence merely to satisfy packaging. Electron’s first-app documentation identifies author, licence and description as necessary for later packaging. Complete this metadata check before running the import or make commands above.

npx create-electron-app@latest import
npm run make

Import changes project configuration and dependencies. Inspect those changes rather than treating it as a read-only operation. Forge adds packaging scripts and configuration; makers produce the relevant distribution formats. Do not assume that one successful build proves compatibility with every target system. Packaging, platform signing, installation checks and update delivery require their own decisions.

Stage Evidence to retain What it does not establish
Project setup Manifest and lockfile A working window
Local launch Window and terminal observations An installable release
Package creation Output artefact and maker configuration Signing or user acceptance
Release assessment Target-system installation and lifecycle results Indefinite maintenance

Original contribution: collection-desk release worksheet

Use SAMPLE-COLLECTION as a worked acceptance record. Write the action, expected behaviour, observed behaviour and next owner for each scenario. Opening the app should show the fictional reference. Closing all windows should follow the target platform’s intended lifecycle. Reactivating on macOS should recreate the window when none remain. A missing local page should produce a recorded defect rather than a silently approved release.

Extend the worksheet before adding real data: what happens when a collection is cancelled, when the computer is shared and when a record must be removed? Our static example cannot demonstrate those controls. Mark them as unimplemented requirements rather than inferring them from a window that opens successfully. This prevents a prototype becoming an operational promise by accident.

For handover, identify the supported targets, package owner, update route and recovery instructions. Store actual observations separately from the expected results above. Discuss the wider interface through web development and its business context through web design. To define a bounded desktop project, get started with the worksheet and fictional examples.

By Spout Team. AI-assisted drafting by Codex using the linked primary sources.

Make your next move.

A website, a store or a clearer digital plan. Let’s start with your business.

Start your brief