---
title: Encrypting SQLite databases in Capacitor
description: Learn how to encrypt SQLite databases in Capacitor applications using 256-bit AES encryption and secure key management with the Capacitor SQLite plugin.
date: 
  created: 2025-07-24
  updated: 2026-07-17
authors:
  - robingenz
categories:
  - Capacitor
  - Guides
  - SDKs
links:
  - Capacitor SQLite: sdks/capacitor/sqlite.md
  - Capacitor Secure Preferences: sdks/capacitor/secure-preferences.md
faq: true
---

# Encrypting SQLite databases in Capacitor

This guide shows how to encrypt SQLite databases in Capacitor using the [Capacitor SQLite plugin](../../sdks/capacitor/sqlite.md) with 256-bit AES and secure key management via the [Capacitor Secure Preferences plugin](../../sdks/capacitor/secure-preferences.md). For full Capacitor SQLite plugin documentation, see the [plugin docs](../../sdks/capacitor/sqlite.md).

<!-- more -->

## Introduction

SQLite databases in mobile applications often contain sensitive user data such as personal information, authentication tokens, or financial records. Without proper encryption, this data remains vulnerable to unauthorized access if a device is compromised. The [Capacitor SQLite plugin](../../sdks/capacitor/sqlite.md) provides 256-bit AES encryption, so the database stays unreadable without the key.

Combined with the [Capacitor Secure Preferences plugin](../../sdks/capacitor/secure-preferences.md) for secure key storage, you protect both your data and the encryption keys used to secure it.

This post focuses on encryption specifically. If you also need the surrounding setup (opening databases, schema migrations, transactions, and where encryption fits in a full integration), see [How to Use SQLite in a Capacitor App](./how-to-use-sqlite-in-a-capacitor-app.md).

## Installation

To implement database encryption in your Capacitor application, you'll need to install and configure both the Capacitor SQLite plugin (with encryption support) and the Capacitor Secure Preferences plugin for secure key management.

### Secure Preferences

The Capacitor Secure Preferences plugin provides secure storage for sensitive information like encryption keys using the [Android Keystore](https://developer.android.com/privacy-and-security/keystore){:target="_blank"} and [iOS Keychain](https://developer.apple.com/documentation/security/keychain-services){:target="_blank"}. To install the plugin, please refer to the [Installation](../../sdks/capacitor/secure-preferences.md/#installation) section in the plugin documentation.

### SQLite

The Capacitor SQLite plugin supports encryption through SQLCipher integration. To install the plugin with encryption support, please refer to the [Installation](../../sdks/capacitor/sqlite.md/#installation) section in the plugin documentation.

**Important**: Make sure to enable SQLCipher support during installation by configuring the platform-specific settings as described in the plugin documentation.

## Usage

Let's walk through the steps to encrypt a SQLite database in your Capacitor application.

### Generating the encryption key

First, you need to generate a secure encryption key. This key will be used to encrypt and decrypt the database. Use a strong, unique key for each database instance. You have several options for generating this key:

1. **Generate a random key on the client**: Use a cryptographically secure random number generator to create a 256-bit key.
2. **Generate a random key on the backend**: Generate the key on your backend server and securely transmit it to the client application.
3. **Use a user-provided key**: Allow users to set their own encryption key, but ensure it meets security standards (e.g., 256 bits).

As an example, here's how to generate a random key on the client using the Web Crypto API:

```typescript
const generateEncryptionKey = async (): Promise<string> => {
  // Use a secure random number generator to create a 256-bit key
  const key = new Uint8Array(32); // 256 bits = 32 bytes
  window.crypto.getRandomValues(key);
  return Array.from(key).map(b => b.toString(16).padStart(2, '0')).join('');
};
```

This function generates a random 256-bit key and returns it as a hexadecimal string. You can call this function when you need to create a new database or change the encryption key.

### Storing the encryption key

Next, you need to securely store the encryption key since it will be required every time you open the database. You can use the Capacitor Secure Preferences plugin to store the key securely on the device:

```typescript
import { SecurePreferences } from '@capawesome-team/capacitor-secure-preferences';

const getEncryptionKeyFromSecurePreferences = async (): Promise<string | null> => {
  const { value } = await SecurePreferences.get({ key: 'encryptionKey' });
  return value;
};

const setEncryptionKeyInSecurePreferences = async (key: string): Promise<void> => {
  await SecurePreferences.set({ key: 'encryptionKey', value: key });
};

const getEncryptionKey = async (forceNew: boolean = false): Promise<string> => {
  // Retrieve the encryption key from secure preferences
  let encryptionKey = await getEncryptionKeyFromSecurePreferences();
  if (!encryptionKey || forceNew) {
    // Generate a new encryption key if it doesn't exist or if forced
    encryptionKey = await generateEncryptionKey();
    // Store the new key securely
    await setEncryptionKeyInSecurePreferences(encryptionKey);
  }
  return encryptionKey;
};
```

The `getEncryptionKey(...)` function retrieves the encryption key from secure preferences, generating a new one if it doesn't exist or if forced.

### Encrypting the database

Now that you have a secure encryption key, you can open an encrypted SQLite database using the Capacitor SQLite plugin. For this, you'll use the `open(...)` method with the `encryptionKey` option:

```typescript
import { Sqlite } from '@capawesome-team/capacitor-sqlite';

const openEncryptedDatabase = async () => {
  const encryptionKey = await getEncryptionKey();

  const { databaseId } = await Sqlite.open({
    encryptionKey,
    path: 'db.sqlite3'
  });
  
  return databaseId;
};
```

The `open(...)` method opens the database with the specified encryption key. It's not yet possible to encrypt an already existing database with the plugin. You must create a new database with the encryption key from the start. As a workaround, you can create a new encrypted database and then copy the data from the old unencrypted database to the new one.

### Changing the encryption key

If you need to change the encryption key for an existing database, you can do so using the [`changeEncryptionKey(...)`](../../sdks/capacitor/sqlite.md#changeencryptionkey) method. This method allows you to update the encryption key while keeping the existing data intact:

```typescript
const changeKey = async (databaseId: number) => {
  const encryptionKey = await getEncryptionKey(true);

  await Sqlite.changeEncryptionKey({
    databaseId,
    encryptionKey,
  });
};
```

By passing `true` to the `getEncryptionKey(...)` function, you force it to generate a new key. The `changeEncryptionKey(...)` method updates the database with the new key.

## Best Practices

### Use Strong, Unique Encryption Keys

Generate cryptographically secure random keys for each database. Avoid using predictable keys based on user passwords or device identifiers. Use platform-specific secure random number generators and ensure keys are at least 256 bits in length.

### Implement Key Rotation

Regularly rotate encryption keys to minimize the impact of potential key compromise. Implement a key rotation strategy that can migrate data from old keys to new ones without data loss.

### Handle Key Loss Gracefully

Design your application to handle scenarios where encryption keys are lost or corrupted. Implement backup strategies and user recovery mechanisms, and make sure the fallback procedures don't compromise security.

## FAQ

### Can I encrypt a database I already have running in production, without recreating it?

Not directly. The plugin doesn't support encrypting an already-existing unencrypted database in place. The workaround is to create a new database with the encryption key set from the start, then copy the data over from the old unencrypted database into the new encrypted one.

### Where should the encryption key actually live: hardcoded, generated on-device, or from the backend?

Avoid hardcoding it in your app's source code in every case. That defeats the purpose of encryption, since anyone can extract it from the installed app. The three legitimate options are generating a random key on the client, generating it on your backend and transmitting it securely, or letting users set their own key that meets a minimum strength requirement. Whichever you choose, store the resulting key with Secure Preferences, not in a JS variable or config file.

### If I lose the encryption key, can I recover the data?

No. This is the direct trade-off of encryption done correctly. If the key is genuinely lost (not just misplaced in secure storage, but actually gone), the encrypted data is unrecoverable by design. This is why the guide's best practices call out designing a backup or recovery strategy specifically for key loss scenarios, rather than assuming secure storage never fails.

### Does rotating the encryption key with `changeEncryptionKey()` require re-encrypting all the data manually?

No. That's exactly what the method handles for you. `changeEncryptionKey()` updates the database's encryption key while keeping the existing data intact, so you don't need to export, delete, and reimport records to rotate keys; you just generate a new key and pass it to this method.

### Is 256-bit AES encryption enough, or do I still need to worry about how the key itself is protected?

The encryption algorithm's strength doesn't help if the key protecting it is weak or poorly stored. A 256-bit AES-encrypted database is only as secure as the key guarding it — a predictable key (derived from a password or device ID) or a key stored in plaintext undermines the encryption regardless of algorithm strength, which is why this guide pairs SQLite encryption with Secure Preferences for the key itself.

## Conclusion

If your app keeps personal information, authentication tokens, or financial records in SQLite, set the encryption key on the first `open(...)` call instead of retrofitting encryption later. The [Capacitor SQLite plugin](../../sdks/capacitor/sqlite.md) cannot encrypt an existing database in place, so a retrofit means copying the data into a new database. Store the key with the [Capacitor Secure Preferences plugin](../../sdks/capacitor/secure-preferences.md) from the start, and decide on your key rotation and key loss strategy before you ship.

**Related reading:**

- [Exploring the Capacitor SQLite API](./exploring-the-capacitor-sqlite-api.md)
- [Key-Value Storage with the SQLite plugin](./key-value-storage-made-simple-with-the-sqlite-plugin.md)
- [Plugin documentation](../../sdks/capacitor/sqlite.md#api)

If you have any questions or need assistance with Capacitor SQLite database encryption or database security, feel free to reach out to the Capawesome team.


To stay updated with the latest updates, features, and news about the Capawesome, Capacitor, and Ionic ecosystem, subscribe to the [Capawesome newsletter](/newsletter/){:target="_blank"} and follow us on [X (formerly Twitter)](https://x.com/capawesomeio){:target="_blank"}, and join the [Capawesome Discord server](https://discord.gg/VCXxSVjefW){:target="_blank"} for updates and support.
