Publishing Electron apps to GitHub with Electron Forge
Tags: node, electron, githubactions
Published: 2023-07-19 20:18:09

---
title: Publishing Electron apps to GitHub with Electron Forge
published: true
tags: ['node', 'electron', 'githubactions']
canonical_url: https://sevic.dev/notes/electron-forge-publish-github/
---

Releasing Electron desktop apps can be automated with Electron Forge and GitHub Actions. This post covers the main steps for automation.

### Prerequisites

- bootstrapped Electron app
- GitHub personal access token (with `repo` and `write:packages` permissions) as a GitHub Action secret (`GH_TOKEN`)

### Setup

Run the following commands to configure Electron Forge for the app release.

```bash
npm i @electron-forge/cli @electron-forge/publisher-github -D
npx electron-forge import
```

The last command should install the necessary dependencies and add a configuration file.

Update the `forge.config.js` file with the `bin` field containing the app name and ensure the GitHub publisher points to the right repository.

Put Windows and MacOS icons paths in the `packagerConfig.icon` field, Windows supports `ico` files with 256x256 resolution, and MacOS supports `icns` icons with 512x512 resolution (1024x1024 for Retina displays). Linux supports `png` icons with 512x512 resolution, also include its path in the `BrowserWindow` constructor config within the `icon` field.

```js
// forge.config.js
const path = require('path');

module.exports = {
  packagerConfig: {
    asar: true,
    icon: path.join(process.cwd(), 'main', 'build', 'icon'),
  },
  rebuildConfig: {},
  makers: [
    {
      name: '@electron-forge/maker-squirrel',
      config: {
        bin: 'Electron Starter'
      }
    },
    {
      name: '@electron-forge/maker-dmg',
      config: {
        bin: 'Electron Starter'
      }
    },
    {
      name: '@electron-forge/maker-deb',
      config: {
        bin: 'Electron Starter',
        options: {
          icon: path.join(process.cwd(), 'main', 'build', 'icon.png'),
        },
      }
    },
    {
      name: '@electron-forge/maker-rpm',
      config: {
        bin: 'Electron Starter',
        icon: path.join(process.cwd(), 'main', 'build', 'icon.png'),
      }
    }
  ],
  plugins: [
    {
      name: '@electron-forge/plugin-auto-unpack-natives',
      config: {}
    }
  ],
  publishers: [
    {
      name: '@electron-forge/publisher-github',
      config: {
        repository: {
          owner: 'delimitertech',
          name: 'electron-starter'
        },
        prerelease: true
      }
    }
  ]
};
```


Upgrade the package version before releasing the app. The npm script for publishing should use publish command. Set `productName` field to the app name.

```json
// package.json
{
  // ...
  "version": "1.0.1",
  "scripts": {
    // ...
    "publish": "electron-forge publish"
  },
  "productName": "Electron Starter"
}
```

GitHub Action workflow for manually releasing the app for Linux, Windows, and MacOS should contain the below configuration.

```yml
# .github/workflows/release.yml
name: Release app

on:
  workflow_dispatch:

jobs:
  build:
    strategy:
      matrix:
        os:
          [
            { name: 'linux', image: 'ubuntu-latest' },
            { name: 'windows', image: 'windows-latest' },
            { name: 'macos', image: 'macos-latest' },
          ]

    runs-on: ${{ matrix.os.image }}

    steps:
      - name: Github checkout
        uses: actions/checkout@v4

      - name: Use Node.js
        uses: actions/setup-node@v4
        with:
          node-version: 20

      - run: npm ci

      - name: Publish app
        env:
          GITHUB_TOKEN: ${{ secrets.GH_TOKEN }}
        run: npm run publish
```

### Windows startup events

Add the following code in the main process to prevent Squirrel.Windows launches your app multiple times during the installation/updating/uninstallation.

```js
// main/index.js
if (require('electron-squirrel-startup') === true) app.quit();
```

### Boilerplate

Here is the [link](https://sevic.dev/electron-starter?ref=devto) to the boilerplate I use for the development. It contains the examples mentioned above with more details.