How to Keep an Electron App Running in the Background

Sometimes, you may need your Electron-based app to still be running in the background while hidden from the user. Some use-cases are: To receive push notifications, quick relaunch etc.

What does ‘background’ mean?

As you may already know, there’re two processes in Electron; Renderer and Main. Renderer process is responsible for showing the ‘content’ in the Window. Think of the Renderer as the client-side of the app. Main is the actual background process that does the stuff that we’d normally do on the server-side.

So when we’re talking about running Electron in the background, we mean to only keep the Main process running and hide all the renderer process. It’s that simple (Well, not that simple). Let’s see how can we achieve it.

What are our options?

We can simply hide all the windows of the app and not call app.quit(). That should work, right? But it doesn’t. Even if all the windows are closes/hidden, the app’s icon will stay in the dock or the startbar of the platform. Which the user can click to re-launch the app or right-click and quit it completely which we do not want.

You may be thinking that: Well, we could use something like this:

app.on(‘window-all-closed’, app.dock.hide)

And you’d be right my good madam (or sir)! But .dock is only available on macOS and even if we used a similar solution for other platforms, we’ll have yet another problem related to UX; Users will have no idea if the app is running or not. So if they wanted to quit the app or relaunch, what would be their options?

I’ve seen another pattern in the Electron community and the industry as the possible solution; Tray menu.

Example code to create a tray menu in electron app

As the name suggests, the menu stays in the “system tray” of the OS. For macOS that is the top menu bar and for Windows it’s the bottom-right of the startbar.

Example of a Tray menu icon on macOS and the contents shown after it is clicked

Similar to the dock, only an icon is visible in the Tray and it shows a menu when clicked. You can also show an entire window attached to the icon, but we’re not going to cover that in this article.

Keeping Electron App in Background

So now to the actual steps and code to keep an Electron app running in the background:

  1. Listen to the window-all-closed event on app and to not quit the app, but instead hide all the renderer windows and the icon in the dock.
  2. Create or simply keep the Tray menu.
  3. Recreate a window when the users ask for it from the tray menu.

1. For the first point, it’s simple. Instead of doing this, like we normally do:

app.on(‘window-all-closed’, () => { app.quit() })

We’re going to do:

app.on(‘window-all-closed’, () => {
app.dock.hide() // for macOS
// use same logic for other OSes you want

2. Create or keep the Tray menu. We can either create the Tray menu when launching the app or create it only when all the windows are closed in step 1. I’ll just create it when starting the app. Remember: the icon is required for a Tray menu.

3. Menu in the Tray. I’m just adding two options in the context menu of the Tray, one is to show the app, and other is to completely quit the app.

Running this code is going to create a Window and the Tray. Tray will still there even when all the windows are closed. User will still have the control over completly quitting the app.

I changed the push notifications quick start code a little to add the Tray-related code. You’re welcome to use or change it however you want.

If you have any other technique that tackles the UX as well as the functionality, please do let me know!

Related read: Learn how to add push notifications to Electron apps.

👉🏼 Follow me on Twitter for more technical stuff.

ProductHunter. Learning UI/UX. Wantrepreneur.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store