October 12, 2021
  • Tutorials
  • Ionic
  • storage

Choosing the Right Data Storage Solution: Ionic Storage, Capacitor Preferences, SQLite, or Ionic Secure Storage?

Simon Grimm

ionic storage

This is a guest post from Simon Grimm, Ionic Insider and educator at the Ionic Academy. Simon also created the Practical Ionic book, a guide to building real world Ionic applications with Capacitor and Firebase.

Updated: June 14, 2023

You want to store data locally in your Ionic application? It’s a simple task usually, given the available tools these days like Ionic Storage, Capacitor Preferences, or just the app’s inherent SQLite database.

But what’s actually the difference between these storage options? How does your storage engine selection affect your app, what should be stored, and which engine provides the best results for your specific needs?

Today we will explore the differences between Ionic Storage, Capacitor Preferences, plain SQLite storage, and Ionic’s Secure Storage solution. We’ll look under the hood to understand how they work and what makes them great.

In the end I’ll give recommendations for each scenario so you can get the most out of your Ionic application!

Ionic Storage

Probably the most common way to store data for Ionic developers is Ionic Storage. While it was only available for Angular projects in the past, you can use Ionic Storage with all frameworks since version 3!

At its core, Ionic Storage is a key-value Storage module for Ionic apps.

constructor(private storage: Storage) { }

setData(value: any) {
    // Store the value under "my-key"
    this.storage.set('my-key', value);
}

getData() {
    // Get the value under "my-key"
    this.storage.get('my-key');
}

You can throw any data or object into it, and the information will be stored.

But where?

That’s one of the biggest arguments in favour of Ionic Storage; Ionic Storage will automatically select the best possible underlying storage engine available on the current platform.

Normally this means IndexedDB or otherwise localstorage. On top of that, you can install a SQLite driver so within a native iOS or Android app, SQLite will be used instead.

All of this will then happen automatically, and you can run/test your application both on the web and on mobile devices without noticing any difference and the same code!

The biggest plus of Ionic Storage is the ease of use across all platforms with the same API, while even allowing access to the SQLite database of an app on a real device.

If your app is only using localstorage or IndexedDB, the underlying OS might clear your data at any time which makes these options not 100% persistent and safe.

Although the usage is easy, there is no way to query specific data, and you can only retrieve all the information stored under a specific key. Still, that information could be anything you want up to medium-sized data, as with bigger objects the loading takes longer and performance decreases.

Capacitor Preferences

Capacitor Preferences is probably overlooked many times due to the popularity of Ionic Storage in the past, but it offers a safe and reliable way to store small chunks of data in a persistent way on iOS and Android.

This plugin will use UserDefaults on iOS and SharedPreferences on Android. These native classes are mostly used to define the default app state and are 100% persistent as the data is stored directly inside the OS settings.

However, this might come at a cost, as the Android class has a dedicated note about it:

“​​This class provides strong consistency guarantees. It uses expensive operations which might slow down an app”

From the outside, the usage looks mostly like that of a key-value storage:

import { Preferences } from '@capacitor/preferences';

setData(value: string) {
    // Store the value under "my-key"
    Preferences.set({ key: 'my-key', value: value });
}

getData() {
    // Get the value under "my-key"
    Preferences.get({ key: 'my-key' });
}

The tiny difference is that you can only store strings with Capacitor Preferences!

That doesn’t mean you can’t store any other objects, but you would have to stringify them when storing them and parse them back to an object when loading the data. Again, this might slow down your performance:

setData() {
    const user = {
        name: 'Simon',
        age: 31,
        country: 'Germany'
    };

    Preferences.set({key: 'my-key', value: JSON.stringify(user) });
}

async getData() {
    const { value } = await Preferences.get({ key: 'my-key' });
    const user = JSON.parse(value);
}

You can of course also use Capacitor Preferences on the web, but the plugin will fall back to the more unstable localstorage engine inside a Progressive Web App.

Because we can only store strings and the operations to access the data from the native OS classes are potentially less performant, this option is not meant as a replacement for your local database.

It’s a safe and reliable way to save things like user selected app language, colors or other preferences, but just like Ionic Storage, there’s no querying of data available.

SQLite

Didn’t we already talk about SQLite when we looked at Ionic Storage? Yes and no.

The truth is, you can add an SQLite driver to Ionic Storage to use it on a device. However, you are not really accessing the real power of the underlying SQLite database because you can’t run SQL queries—you are limited to the key/value API.

This option is also only available for native apps, either as a Cordova plugin or more recommended with a Capacitor plugin. For the web, none of these will work and you’d have to find a different solution.

However, the inherent SQLite database inside every mobile app can be quite powerful, and by directly accessing it with a plugin you can tap into all functionalities.

This means, by using one of those plugins you can create more complex queries to retrieve the right information from your database using SQL:

getUsers() {
    return this.sqlite.execute({ statements: "SELECT * FROM users WHERE company IS ‘Ionic’;" });
}

Some plugins even offer a way to import a JSON dump into your local database, or you could have some seed statements to initially create and fill the database.

This option is only recommended if you know how to write SQL and your app needs to work with a lot of data where querying the local database makes sense to improve the performance.

If your only intention is to store and retrieve all data without any filtering, update or other querying, directly using SQLite is likely not giving you any benefit over the previous options.

Also be aware that SQLite is indeed a lite version of a regular SQL database and only comes with a limited amount of data types.

Security-Sensitive Apps

Teams building security-sensitive applications requiring encryption should consider Ionic Secure Storage, an enterprise-ready, high-performance data store. In addition to the benefits that the community plugins also based on SQLite offer, Secure Storage has 256-bit AES encryption, one API covering multiple use cases (you can choose between key/value or SQL approaches), and Ionic’s support and advisory services are included.

When to use which data storage?

All four of these solutions are decent choices for your Ionic app. However, you want to optimize your apps performance and reliability so you should base your choice on these questions:

  1. How large is the amount of data I need to store?
  2. On which platforms should my app run?
  3. Do I need more functionality than standard save/load?
  4. Am I building a security-sensitive app?

Data

If you only want to store some small settings, go with Capacitor Preferences. If there’s more information you want to store including bigger objects, Ionic Storage will usually work better.

Since Ionic Storage and direct SQLite are basically the same (both storing data in SQLite on a device) when it comes to the amount of data, you have to calculate the other factors as well!

Platforms

Using the native SQLite plugins requires your Ionic app to run as an app on iOS or Android. If your app should also be available as a PWA, using Ionic Storage with a persistent API across all platforms will likely work better.

Also, Capacitor Preferences only really shines when used inside a native app where you can access the OS settings.

Querying

Both Ionic and Capacitor Preferences are meant to easily store and read data without any bigger logic involved. When your amount of data exceeds a certain limit and you rather want to query a subset of your data instead of loading everything at once, using the direct SQLite integration instead is the logical choice.

Security

If your app needs to store large amounts of sensitive data, reach for Secure Storage. No company should risk the consequences: data loss, unauthorized account access, angry customers, brand damage, and more. Additionally, keeping up with security best practices over time can be tricky given all the other work we developers are expected to do.

Otherwise, community options work well for less sensitive data and use cases.

Choosing the right data storage solution

There is no one-size-fits-all solution to selecting the right storage engine for your Ionic app.

Just like some projects are better off with React, Vue or Angular, you need to understand the needs of your app and make a choice based on the different factors and your specific requirements.

Besides that, there are other options available that we haven’t discussed in this post like PouchDB which is following a NoSQL approach of a local JS database instead.

For everyone who wants to explore all options and build better Ionic apps, I’m also running a full online school with 60+ Ionic video courses, templates and a supportive community — go check out the Ionic Academy and get access to a ton of learning material to boost your Ionic and Capacitor development skills today.

PS: And don’t forget to subscribe to my YouTube channel for fresh Ionic tutorials coming every week!


Simon Grimm