How to store user data in Electron

The 3 most common ways to persist user data with an example

· 3 min read
Many file folders side by side

Code in this article can be found here: https://github.com/ccnokes/electron-tutorials

Most Electron apps need some sort of way to save user data. This could be user preferences (e.g. show/don’t show notifications) or some kind of application data (e.g. last window size and position). So how do we save user settings in an Electron app? And where do we save them to?

Because we have access to both browser and node.js APIs, we have some options for persisting user data. Let’s go over them and then we’ll look at a practical example.

HTML5 Storage APIs (localStorage and IndexedDB)

If you primarily access your data in the renderer process, this is the simplest solution. You can access HTML5 storage data from the main process via electron-remote, which provides an asynchronous API to a hidden browser window that can execute DOM/renderer specific code. One drawback to this might be the fact that the API you use to get/set your user data in the main (async) will be different from the what is in the renderer (sync). This is a pretty attractive solution, and one I plan to play around with.

Flat file

If we want to access that data easily from both the renderer and main, using the same API, we can use the node.js fs (file system) module to save data to a JSON file (or any format we want). This approach covers the most common use cases, so we’ll cover how to do this in an example in a moment.

Embedded database

If we have larger data storage needs there are “embedded” databases like neDB (implements the Mongo API) or sqlite that we could use. Note that this could introduce some complexity because sometimes these databases (like sqlite) are native node modules (they use C++), and shipping cross-platform native code, even through NPM, can have some gotchas. Most applications that I’ve seen/heard of don’t have such complicated storage needs, but I’m sure there’s some use cases for it.

Where should I store the data?

Typically data is stored in the user’s “app data” folder. Where this directory is varies by operating system.

  • Mac OS: ~/Library/Application Support/<Your App Name (taken from the name property in package.json)>
  • Windows: C:\Users\<you>\AppData\Local\<Your App Name>
  • Linux: ~/.config/<Your App Name>

Electron provides app.getPath which returns the right directory, depending on your platform.

Why not store the user data closer to all our app’s source files?

Storing user data in the operating system’s designated location for user’s app data is the idiomatic way for native app’s to persist user data because:

  • when we auto-update the app, our source files may get moved or delete

  • changing or adding to an app’s internal files will invalidate the code signature

Let’s persist some data (example)

I think the most common use cases are covered by storing our data as JSON in the user data directory. Let’s see how we could implement a module in our app that could handle saving/loading the size of the window. When we resize the window, we’ll save the new size to a file. When the app starts, we’ll load that file, and pass in the saved size to our BrowserWindow instance.

Let’s encapsulate the data getting and setting logic in a class called Store. The main things this class needs to do is read/write to a file and get/set values. We’ll also make it so that it can work in either the renderer or main process. When it saves the file, it needs to save the file to the user’s app data directory. We’ll make it so our class takes an options object as the first argument. We’ll pass in the data file name and some defaults in the options.

Ok that’s it. Pretty simple. Now let’s integrate it into our app.

All done. Now let’s start our app up and test it out.

Resizing the window will cause the file to be written. It should look something like:

{
  "windowBounds": {
    "width": 427,
    "height": 289
  }
}

Our Store class is actually compatible with a community module called electron-config (yep, we implemented the same API), and it’s a great module with more features and test coverage.

Saving the window’s position and size is a common use case in Electron apps. Another convenient community module that handles this is electron-window-state.

There you have it!