sssf-capacitor-sqlite
v8.2.0-sssf.3
Published
Community plugin for native & electron SQLite databases
Maintainers
Readme
This is a fork:
sssf-capacitor-sqliteA fork of
@capacitor-community/sqlitewhose Web implementation has been rewritten. Native (iOS, Android) and Electron track upstream, and additionally carry only those changes this fork already has open as upstream pull requests, so they retire on their own when upstream merges. Nothing native is invented here. Right now that means capacitor-community/sqlite#696: SQLCipher pinned on both iOS dependency managers, with Swift Package Manager as the verified path.What changed. The web engine was
jeep-sqlite, a Stencil element wrappingsql.jsin memory with whole-database images in IndexedDB, last published in August 2024. This fork replaces it with the official@sqlite.org/sqlite-wasmbuild running in a dedicated worker, storing databases as real files in the Origin Private File System through theopfs-sahpoolVFS, with an automatic IndexedDB fallback for browsers that lack OPFS sync access handles. Existingjeep-sqlitedata is migrated once, automatically. It ships with a browser test suite that runs every contract test on both storage tiers.Why a fork exists at all. The work is offered upstream, and the fork is meant to be retired rather than maintained: see the upstream discussion at capacitor-community/sqlite#693. Switch back to
@capacitor-community/sqliteas soon as upstream merges it. Nothing in the public API differs, so switching back is a dependency change and a reinstall.Never install this alongside
@capacitor-community/sqlitein one app. The iOS pod and the Android Gradle module keep their upstream identities, so two copies collide at the native build level rather than failing cleanly. Remove one before adding the other.Upstream README follows unchanged.
Maintainers
| Maintainer | Company | GitHub | Social | | ---------- | ----------------------------------- | ----------------------------------------- | --------------------------------------------- | | Robin Genz | Capawesome | robingenz | @robin_genz |
Installation
[!IMPORTANT]
This plugin uses the SQLCipher library (even for unencrypted databases), which is subject to the Encryption Export Regulations and may require you to submit a year-end self-classification report to the U.S. government. Read more here.
npm install --save @capacitor-community/sqlite
npx cap syncyarn add @capacitor-community/sqlite
npx cap syncpnpm install --save @capacitor-community/sqlite
npx cap syncOn iOS the plugin supports both Swift Package Manager and CocoaPods, and the two link different SQLCipher versions. See IOS Quirks before you create the iOS project.
then add plugin to main capacitor.config.ts file:
import { CapacitorConfig } from '@capacitor/cli';
const config: CapacitorConfig = {
appId: 'com.jeep.app.ionic7.angular.sqlite',
appName: 'ionic7-angular-sqlite-starter',
webDir: 'www',
server: {
androidScheme: 'https'
},
plugins: {
CapacitorSQLite: {
iosDatabaseLocation: 'Library/CapacitorDatabase',
iosIsEncryption: true,
iosKeychainPrefix: 'angular-sqlite-app-starter',
iosBiometric: {
biometricAuth: false,
biometricTitle : "Biometric login for capacitor sqlite"
},
androidIsEncryption: true,
androidBiometric: {
biometricAuth : false,
biometricTitle : "Biometric login for capacitor sqlite",
biometricSubTitle : "Log in using your biometric"
},
electronIsEncryption: true,
electronWindowsLocation: "C:\\ProgramData\\CapacitorDatabases",
electronMacLocation: "/Volumes/Development_Lacie/Development/Databases",
electronLinuxLocation: "Databases"
}
}
};
export default config;
More Reading:
- Updating to Capacitor 5
- Releases
- Changelog
- Issues
- Capacitor documentation
- Datatypes In SQLite Version 3
- IncrementalUpgradeDatabaseVersion
Tutorials Blog
- JeepQ Capacitor Plugin Tutorials (the Web tutorials there describe the previous
jeep-sqlitesetup, which no longer applies)
Web Quirks
On the Web platform the plugin runs @sqlite.org/sqlite-wasm, the official SQLite build, inside a dedicated Worker that it creates itself. There is nothing to install alongside it and nothing to copy into your assets folder: the worker (dist/web-worker.js) and the SQLite binary (dist/sqlite3.wasm) ship inside the package. Full setup is in Web Usage, which is required reading for the Web platform.
initWebStore() is still mandatory and is still called exactly as before, once, before the first connection.
Where the data lives
initWebStore() picks one of two durability tiers:
| Tier | Storage | When it is used |
| ---- | ------- | --------------- |
| 1 | Real database files in the Origin Private File System, through the opfs-sahpool VFS. Needs no COOP/COEP headers and no SharedArrayBuffer, so it works inside Capacitor WebViews and on ordinary hosting. | Whenever the browser has OPFS sync access handles. |
| 2 | :memory: databases whose whole-file image is written to IndexedDB, the model the previous implementation used. | Automatic fallback when it does not. |
saveToStore() is a no-op on tier 1, where every committed write is already durable, and performs the real image flush on tier 2 (as do close and closeConnection). Calling it unconditionally is the portable pattern. The old <jeep-sqlite> autosave attribute is gone and has no replacement.
Browser support
There are two separate floors, and they mean different things:
| Floor | Chromium / Android WebView | Safari / iOS WebKit | Firefox | What happens below it |
| ----- | -------------------------- | ------------------- | ------- | --------------------- |
| Engine (BigInt, optional chaining, nullish coalescing) | 80 | 14 | 74 | The plugin does not load at all. The failure is a syntax error inside the SQLite build, not a fallback, and no transpiler setting in your app can change it. |
| Durability (OPFS sync access handles) | 108 | 16.4 | 111 | Tier 2 above: everything works, the database is an image in IndexedDB rather than a file. Android WebView reached this in M132, January 2025. |
Who actually lands on tier 2
Tier 2 is chosen at initWebStore() when the browser lacks OPFS sync access handles:
concretely, navigator.storage.getDirectory or
FileSystemFileHandle.prototype.createSyncAccessHandle is missing, or the SQLite build's own
API version check rejects. In browser versions that means Safari / iOS WebKit 14 to 16.3,
Chromium 80 to 107, Firefox 74 to 110, and Android System WebView before M132 (January 2025).
Two version-independent cases: Safari private browsing always runs tier 2 (OPFS is unavailable
there on every Safari version), and a store already owned by another tab is an explicit error,
never a silent drop to tier 2.
How much traffic that is: measured against caniuse-lite 1.0.30001806 (StatCounter data, checked 2026-08), the whole tier 2 version band is about 1.4% of global browser usage: Safari / iOS 14-16.3 at ~0.5%, Chromium 80-107 remnants at ~0.9%, Firefox 74-110 at ~0.01%. Put differently, of the usage that can load this plugin at all, roughly 98% runs tier 1 and under 2% lands on tier 2, and the band shrinks as evergreen browsers update. In-app WebView versions are not visible to StatCounter, so treat WebViews older than M132 (devices without Google Play services, or with WebView updates disabled) as a small qualitative extra on top.
Why the tier stays despite the small share: Capacitor 8 itself supports iOS 15.0+ and Android API 24+ with WebViews as old as Chrome 60, so the platform's official support envelope reaches below the tier 1 floor, and a Capacitor plugin should not fail where Capacitor does not; and Safari private browsing is tier 2 forever regardless of version, so the tier is the difference between an app that works ephemerally in a private tab and one that is simply broken there.
Other things worth knowing
- One tab at a time. OPFS access handles are single-owner by design, so
initWebStore()fails with an explicit error if another tab of the same origin already owns the store. - Migration is automatic. The first
initWebStore()after upgrading imports every database left behind by the previousjeep-sqlite/IndexedDB implementation, verifies each one withPRAGMA integrity_check, and only then retires the old store. A failure leaves the old data untouched and warns on the console. - Tier 2 databases follow you up to tier 1. When a browser that lacked OPFS gains it, which is the normal upgrade path for the devices that run on tier 2,
initWebStore()moves the stored images into OPFS and only then removes them. - Foreign keys are enforced, as on every other platform. On a database that participates in sync, a soft delete also applies each constraint's
ON DELETEaction to the children, and to their children. - Backgrounding is handled under Capacitor native: the store is closed and paused before the OS suspends the app, and reopened on return.
pauseWebStore(),resumeWebStore()andrestartWebStore()are there if you would rather drive it fromApp.appStateChange. - Integers above 2^53 are returned as
BigInt. The previous web engine silently lost precision on those.JSON.stringifyrefuses to serialise aBigInt, so code that stringifies query results may needexportToJson, which handles this, or a replacer. - No encryption. There is no SQLCipher build for wasm, so encrypted connections and every secret-related method still reject on Web.
- Read-only connections work on Web, on both tiers.
Web Debugging Tools
Where to look depends on the tier. On tier 1, open DevTools > Application > Storage and browse the Origin Private File System: the databases sit in the .capacitor-sqlite directory, though opfs-sahpool names the files opaquely, so exporting through the plugin is usually easier than reading them in place. On tier 2, they appear in IndexedDB under capacitor-sqlite-store > databases, one whole-file image per key.
Android Quirks
- In case you get the following error when building your app in Android Studio:
x files found with path 'build-data.properties'.You can add the following code toapp/build.gradle:
packagingOptions {
exclude 'build-data.properties'
}See #301 and SO question for more information.
Check/Add the following: Gradle JDK version 21 Android Gradle Plugin Version 8.7.2 In variables.gradle
minSdkVersion = 23 compileSdkVersion = 35 targetSdkVersion = 35In AndroidManifest.xml
<application android:allowBackup="false" android:fullBackupContent="false" android:dataExtractionRules="@xml/data_extraction_rules"In res/xml create a file
data_extraction_rules.xmlcontaining:<?xml version="1.0" encoding="utf-8"?> <data-extraction-rules> <cloud-backup> <exclude domain="root" /> <exclude domain="database" /> <exclude domain="sharedpref" /> <exclude domain="external" /> </cloud-backup> <device-transfer> <exclude domain="root" /> <exclude domain="database" /> <exclude domain="sharedpref" /> <exclude domain="external" /> </device-transfer> </data-extraction-rules>
Electron Quirks
- On Electron, go to the Electron folder of YOUR_APPLICATION
cd electron
npm install --save better-sqlite3-multiple-ciphers
npm install --save electron-json-storage
npm install --save jszip
npm install --save [email protected]
npm install --save crypto
npm install --save crypto-js
npm install --save-dev @types/better-sqlite3
npm install --save-dev @types/electron-json-storage
npm install --save-dev @types/crypto-jsImportant:
node-fetchversion must be<=2.6.7; otherwise you'll get an error running the app.Important: if you are using
@capacitor-community/electron v5- you have to stick to [email protected] till further notice so do:
npm install --save-dev [email protected]
npm uninstall --save-dev electron-rebuild
npm install --save-dev @electron/rebuild
npm install --save-dev [email protected]in electron folder open the
tsconfig.jsonfile and add"skipLibCheck": true,
IOS Quirks
- on iOS, no further steps needed.
Dependency manager: Swift Package Manager or CocoaPods
The iOS side of this plugin ships both a Swift package (Package.swift) and a CocoaPods podspec (CapacitorCommunitySqlite.podspec). Capacitor picks one when the iOS project is created, and that choice decides which SQLCipher build your app links, and therefore which SQLite version it runs.
Swift Package Manager (recommended). This is what npx cap add ios uses by default in Capacitor 8, and it is the path this repository builds in CI.
npx cap add iosIt resolves SQLCipher through SQLCipher.swift, pinned to 4.17.0, whose SQLite baseline is 3.53.3. That is the same SQLCipher release the Android side uses (net.zetetic:sqlcipher-android:4.17.0), so both native platforms stay on one SQLite generation.
CocoaPods (still supported, but frozen). Existing projects keep working unchanged, and a new project can still opt in:
npx cap add ios --packagemanager CocoaPodsThe podspec pins SQLCipher to 4.10.0, whose SQLite baseline is 3.50.4. That pin is a ceiling rather than a preference: SQLCipher 4.11.0 removed CocoaPods support ("Removes CocoaPods support (SQLCipher.podspec.json)" in its CHANGELOG, October 2025), so 4.10.0 is the last version published to the CocoaPods trunk and no newer SQLCipher can reach this path.
The practical difference is the SQLite baseline: 3.53.3 on Swift Package Manager against 3.50.4 on CocoaPods. Both are encrypted by SQLCipher and both are supported; only the Swift Package Manager path will keep moving.
To move an existing CocoaPods project across, Capacitor ships an assistant:
npx cap spm-migration-assistantSupported Methods by Platform
| Name | Android | iOS | Electron | Web | | :--------------------------- | :------ | :--- | :------- | :--- | | createConnection (ReadWrite) | ✅ | ✅ | ✅ | ✅ | | createConnection (ReadOnly) | ✅ | ✅ | ✅ | ✅ | since 4.1.0-7, Web since 8.2.0 | | closeConnection (ReadWrite) | ✅ | ✅ | ✅ | ✅ | | closeConnection (ReadOnly) | ✅ | ✅ | ✅ | ✅ | since 4.1.0-7, Web since 8.2.0 | | isConnection (ReadWrite) | ✅ | ✅ | ✅ | ✅ | | isConnection (ReadOnly) | ✅ | ✅ | ✅ | ✅ | since 4.1.0-7, Web since 8.2.0 | | open (non-encrypted DB) | ✅ | ✅ | ✅ | ✅ | | open (encrypted DB) | ✅ | ✅ | ✅ | ❌ | | close | ✅ | ✅ | ✅ | ✅ | | getUrl | ✅ | ✅ | ❌ | ❌ | | getVersion | ✅ | ✅ | ✅ | ✅ | | execute | ✅ | ✅ | ✅ | ✅ | | executeSet | ✅ | ✅ | ✅ | ✅ | | run | ✅ | ✅ | ✅ | ✅ | | query | ✅ | ✅ | ✅ | ✅ | | deleteDatabase | ✅ | ✅ | ✅ | ✅ | | importFromJson | ✅ | ✅ | ✅ | ✅ | | exportToJson | ✅ | ✅ | ✅ | ✅ | | deleteExportedRows | ✅ | ✅ | ✅ | ✅ | | createSyncTable | ✅ | ✅ | ✅ | ✅ | | setSyncDate | ✅ | ✅ | ✅ | ✅ | | getSyncDate | ✅ | ✅ | ✅ | ✅ | | isJsonValid | ✅ | ✅ | ✅ | ✅ | | isDBExists | ✅ | ✅ | ✅ | ✅ | | addUpgradeStatement | ✅ | ✅ | ✅ | ✅ | Modified 4.1.0-6 | | copyFromAssets | ✅ | ✅ | ✅ | ✅ | | isDBOpen | ✅ | ✅ | ✅ | ✅ | | isDatabase | ✅ | ✅ | ✅ | ✅ | | isTableExists | ✅ | ✅ | ✅ | ✅ | | getTableList | ✅ | ✅ | ✅ | ✅ | | getDatabaseList | ✅ | ✅ | ✅ | ✅ | | getMigratableDbList | ✅ | ✅ | ❌ | ❌ | | addSQLiteSuffix | ✅ | ✅ | ❌ | ❌ | | deleteOldDatabases | ✅ | ✅ | ❌ | ❌ | | moveDatabasesAndAddSuffix | ✅ | ✅ | ❌ | ❌ | | checkConnectionsConsistency | ✅ | ✅ | ✅ | ✅ | | isSecretStored | ✅ | ✅ | ✅ | ❌ | | setEncryptionSecret | ✅ | ✅ | ✅ | ❌ | | changeEncryptionSecret | ✅ | ✅ | ✅ | ❌ | | clearEncryptionSecret | ✅ | ✅ | ✅ | ❌ | | checkEncryptionSecret | ✅ | ✅ | ✅ | ❌ | | initWebStore | ❌ | ❌ | ❌ | ✅ | | saveToStore | ❌ | ❌ | ❌ | ✅ | Web: no-op on OPFS, flushes the image on the IndexedDB tier | | getNCDatabasePath | ✅ | ✅ | ❌ | ❌ | | createNCConnection | ✅ | ✅ | ❌ | ❌ | | closeNCConnection | ✅ | ✅ | ❌ | ❌ | | isNCDatabase | ✅ | ✅ | ❌ | ❌ | | transaction | ✅ | ✅ | ✅ | ✅ | | getFromHTTPRequest | ✅ | ✅ | ✅ | ✅ | since 4.2.0 | | isDatabaseEncrypted | ✅ | ✅ | ✅ | ❌ | since 4.6.2-2 | | isInConfigEncryption | ✅ | ✅ | ✅ | ❌ | since 4.6.2-2 | | isInConfigBiometricAuth | ✅ | ✅ | ❌ | ❌ | since 4.6.2-2 | | getFromLocalDiskToStore | ❌ | ❌ | ❌ | ✅ | since 4.6.3 | | saveToLocalDisk | ❌ | ❌ | ❌ | ✅ | since 4.6.3 | | beginTransaction | ✅ | ✅ | ✅ | ✅ | since 5.0.7 | | commitTransaction | ✅ | ✅ | ✅ | ✅ | since 5.0.7 | | rollbackTransaction | ✅ | ✅ | ✅ | ✅ | since 5.0.7 | | isTransactionActive | ✅ | ✅ | ✅ | ✅ | since 5.0.7 |
Documentation & APIs
Web Usage (required reading for the Web platform)
Applications demonstrating the use of the plugin and related documentation
The sample apps below predate the current Web engine. Their native code is unaffected, but every Web setup step they show (installing
jeep-sqlite, defining the custom element, copyingsql-wasm.wasm) has been removed from the plugin. Follow Web Usage instead.
Ionic/Angular
Web ionic7-angular-sqlite-app Ionic 7 Angular 16 Capacitor 5 SQLite CRUD operations for Web.
Native ionic7-angular-sqlite-app Ionic 7 Angular 16 Capacitor 5 SQLite CRUD operations for iOS, Android and Electron.
angular-sqlite-synchronize-app (Not Updated)
Ionic/Angular TypeORM app (Not Updated)
Ionic/React
Web ionic7-react-sqlite-app Ionic7 React18.2.0 Vite4.3.9 Capacitor 5 SQLite CRUD operations for Web.
Web ionic7-react-sqlite-app Ionic7 React18.2.0 Vite4.3.9 Capacitor 5 SQLite CRUD operations for iOS, Android and Electron.
Ionic/React Capacitor SQLite + TypeORM Example App
Ionic/Vue
Web ionic7-vue-sqlite-app Ionic7 Vue3.2.45 Vite4.3.9 Capacitor 5 SQLite CRUD operations for Web.
Web ionic7-vue-sqlite-app Ionic7 Vue3.2.45 Vite4.3.9 Capacitor 5 SQLite CRUD operations for iOS, Android and Electron.
Vue (Not Updated)
Vue TypeORM app (Not Updated)
SolidJS+Vite (Not Updated)
Nuxt3 + Kysely
Quasar
Web quasar-sqlite-app Quasar2.6.0 Capacitor 5 SQLite CRUD operations for Web.
Native quasar-sqlite-app Quasar2.6.0 Capacitor 5 SQLite CRUD operations for iOS, Android and Electron.
SvelteKit
Dependencies
The iOS and Android codes are using SQLCipher allowing for database encryption. On iOS the version depends on the dependency manager, see IOS Quirks.
The iOS code is using ZIPFoundation for unzipping assets files
The Electron code is using better-sqlite3-multiple-ciphers , electron-json-storage and node-fetch from 5.0.4.
The Web code is using @sqlite.org/sqlite-wasm, the official SQLite wasm build, in a dedicated Worker, with fflate for unzipping assets files.
Contributors ✨
Thanks goes to these wonderful people (emoji key):
This project follows the all-contributors specification. Contributions of any kind welcome!
Credits
A big thank you to Jean Pierre Quéau, who maintained this plugin until version 6.0.0.
