Agent Skills
› tekartik/sqflite
› sqflite-common-ffi-web-setup
sqflite-common-ffi-web-setup
GitHub用于在Flutter或Dart Web项目中集成sqflite数据库支持,通过运行setup命令配置WebAssembly二进制文件和IndexedDB持久化,处理跨平台数据库工厂初始化及Worker设置。
Trigger Scenarios
需要在Web环境下使用SQLite数据库
添加sqflite_common_ffi_web依赖并执行初始化配置
Install
npx skills add tekartik/sqflite --skill sqflite-common-ffi-web-setup -g -y
SKILL.md
Frontmatter
{
"name": "sqflite-common-ffi-web-setup",
"description": "Use when adding sqflite support to a web app (Flutter web or Dart web) with package:sqflite_common_ffi_web: running dart run sqflite_common_ffi_web:setup to install sqlite3.wasm and sqflite_sw.js under web\/, databaseFactoryFfiWeb, databaseFactoryFfiWebNoWebWorker, setting the global databaseFactory behind kIsWeb, database names and IndexedDB persistence, shared worker vs basic worker, importing a database with writeDatabaseBytes, limitations and troubleshooting (missing worker file, port-bound storage, deleteDatabase)."
}
sqflite_common_ffi_web: sqflite in the browser
package:sqflite_common_ffi_web implements the sqflite DatabaseFactory on
the web with package:sqlite3 compiled to WebAssembly. Databases persist in
IndexedDB and SQLite runs in a shared worker (one instance for all tabs). It
needs two binary files served next to the app: sqlite3.wasm and the worker
script sqflite_sw.js, both produced by the package setup command.
dart pub add sqflite_common_ffi_web
dart run sqflite_common_ffi_web:setup # creates web/sqlite3.wasm and web/sqflite_sw.js
import 'package:sqflite_common/sqlite_api.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
Future<void> main() async {
Database db = await databaseFactoryFfiWeb.openDatabase('my_db.db');
await db.execute('CREATE TABLE IF NOT EXISTS Test (id INTEGER PRIMARY KEY, value TEXT)');
await db.insert('Test', {'value': 'hello'});
print(await db.query('Test'));
await db.close();
}
Guidelines
Dependency, binaries and import
- Add
sqflite_common_ffi_web(currently 1.1.x, Dart 3.12,platforms: webonly) todependencies. It depends onsqflite_common_ffiandsqflite_common. - Run
dart run sqflite_common_ffi_web:setupin the project directory after adding the dependency and after every upgrade of the package or ofsqlite3. It builds the shared worker withwebdev(into.dart_tool/sqflite_common_ffi_web/setup/<version>/) and writesweb/sqflite_sw.jsplusweb/sqlite3.wasm(downloaded from thesqlite3.dartGitHub releases, version pinned by the package). Options:--force(-f) rebuild,--dir <dir>output directory (defaultweb),--verbose,--no-sqlite3-wasm(skip the wasm download),--sqlite3-wasm-url <url>, and an optional project path argument. Commit the two files or add them to.gitignoreand run setup in CI; either way they must be present in the deployed site root. - The same setup is callable from Dart:
setupSqfliteWebBinaries(options: SqfliteWebSetupOptions(...))frompackage:sqflite_common_ffi_web/setup.dart(path,dir,force,verbose,sqlite3WasmUri,noSqlite3Wasm,sqlite3WasmFilename,sqfliteWebWorkerFilename). io only. - Import
package:sqflite_common_ffi_web/sqflite_ffi_web.dart. It exports only the web factories and options (databaseFactoryFfiWeb,databaseFactoryFfiWebNoWebWorker,databaseFactoryFfiWebBasicWebWorker,createDatabaseFactoryFfiWeb,SqfliteFfiWebOptions,SqfliteFfiWebContext,sqfliteFfiWebLoadSqlite3Wasm,sqfliteFfiWebStartSharedWorker,sqliteFfiWebDebugWebWorker). TheDatabase/DatabaseFactorytypes come frompackage:sqflite_common/sqlite_api.dart(Dart web),package:sqflite_common_ffi/sqflite_ffi.dartorpackage:sqflite/sqflite.dart(Flutter), so import one of them too. - The file compiles on io too (the getters throw
UnsupportedErrorthere), so importing it from shared code is fine as long as the factory is only touched whenkIsWeb/identical(0, 0.0)is true.
Choosing the factory
databaseFactoryFfiWeb(tagffi_web): SQLite runs in aSharedWorkerloaded fromsqflite_sw.js; all tabs of the origin share one SQLite instance, so it is cross-tab safe. WhenSharedWorkeris unavailable (Android Chrome) it silently falls back to a dedicatedWorker, which is not cross-tab safe. This is the default choice.databaseFactoryFfiWebNoWebWorker: loadssqlite3.wasmin the main thread; no worker file needed, but long queries block the UI and several tabs writing the same database can corrupt it. Use for tools, demos or when workers cannot be served.databaseFactoryFfiWebBasicWebWorker: testing only (forces a dedicatedWorker).- The worker and wasm are loaded lazily on the first factory call from
sqflite_sw.js/sqlite3.wasmrelative to the page URL. With a non-root<base href>or another location, passsharedWorkerUri/sqlite3WasmUrithroughcreateDatabaseFactoryFfiWeb(options: SqfliteFfiWebOptions(...))(seesqflite-common-ffi-web-options). - Flutter app that already uses
sqfliteon mobile: keep the code, setdatabaseFactory = databaseFactoryFfiWeb;once at startup whenkIsWeb, before the firstopenDatabase. The globalopenDatabase()then works on all platforms. Usesqflite_common_ffi(databaseFactoryFfi) for the desktop counterpart.
Paths and persistence
getDatabasesPath()returns/and relative paths are used as is: a database name such asmy_db.dbis a key in the virtual file system, not a file. Do not build paths withpath_provideron the web.- Storage is an IndexedDB database named
sqflite_databases(override withSqfliteFfiWebOptions.indexedDbName) holding every sqflite database of the origin. IndexedDB is per origin including the port:localhost:8080andlocalhost:8081are different stores, so always debug on the same port. There is no OPFS backend. inMemoryDatabasePathopens a private in-memory SQLite database inside the worker (nothing stored).- To import a bundled database (asset or download), write its bytes with
factory.writeDatabaseBytes(path, bytes)thenopenDatabase(path);readDatabaseBytes(path)exports it.databaseExists,deleteDatabasework on the virtual file system. sqfliteFfiInit()fromsqflite_common_ffiis a no-op on the web; calling it in shared code is harmless.
Limitations
- Experimental: slower than native, larger message overhead (each call goes
through
postMessage), not fully tested. - dart2wasm (
flutter build web --wasm) is supported since 1.2.0 withsqflite_common2.5.13 or later; with older versionsdeleteDatabaseanddatabaseExistssilently fail when the app is compiled with dart2wasm. - Basic
Workerfallback (Android Chrome) is not cross-tab safe. - One connection per database:
OpenDatabaseOptions(singleInstance: false)throws anArgumentErrorfor a persistent database. Every connection of a factory runs in the same wasm instance on the same virtual file system, which has no locking between connections, so a second connection to the same file could corrupt it. Keep the defaultsingleInstance: true(the sameDatabaseis returned for the same path); onlyinMemoryDatabasePathcan be opened several times. - Only one worker script name per site: the shared worker is keyed by its
URL, so after upgrading the package all tabs must reload. To force a
reload change the worker file name (see options skill,
sw_js_file).
Examples
Flutter app: web + mobile + desktop
import 'dart:io' show Platform;
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:flutter/widgets.dart';
// sqflite_ffi.dart exports the whole sqflite_common API (openDatabase,
// databaseFactory...); package:sqflite/sqflite.dart would be redundant.
import 'package:sqflite_common_ffi/sqflite_ffi.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
if (kIsWeb) {
databaseFactory = databaseFactoryFfiWeb;
} else if (Platform.isWindows || Platform.isLinux) {
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
}
// Global openDatabase() now works everywhere; on the web the path is a name.
var db = await openDatabase(
'app.db',
version: 1,
onCreate: (db, _) => db.execute(
'CREATE TABLE Note (id INTEGER PRIMARY KEY, text TEXT)',
),
);
await db.insert('Note', {'text': 'hello'});
runApp(const SizedBox());
}
Dart web app (no Flutter)
import 'package:sqflite_common/sqlite_api.dart';
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
Future<void> main() async {
var factory = databaseFactoryFfiWeb;
var db = await factory.openDatabase(
'counter.db',
options: OpenDatabaseOptions(
version: 1,
onCreate: (db, _) =>
db.execute('CREATE TABLE Counter (id INTEGER PRIMARY KEY, value INTEGER)'),
),
);
await db.rawInsert(
'INSERT INTO Counter(id, value) VALUES (1, 0) ON CONFLICT(id) DO UPDATE SET value = value + 1',
);
print(await db.query('Counter'));
await db.close();
}
Importing an asset database on Flutter web
import 'package:flutter/services.dart' show rootBundle;
import 'package:sqflite/sqflite.dart';
Future<Database> openBundledDatabase() async {
const path = 'bundled.db';
if (!await databaseFactory.databaseExists(path)) {
final data = await rootBundle.load('assets/bundled.db');
final bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await databaseFactory.writeDatabaseBytes(path, bytes);
}
return openDatabase(path, readOnly: true);
}
Main-thread factory for a small tool page
import 'package:sqflite_common_ffi_web/sqflite_ffi_web.dart';
Future<String> sqliteVersion() async {
// Only sqlite3.wasm is required, no sqflite_sw.js.
var db = await databaseFactoryFfiWebNoWebWorker.openDatabase('tool.db');
try {
return (await db.rawQuery('SELECT sqlite_version()')).first.values.first
as String;
} finally {
await db.close();
}
}
Common mistakes
- Forgetting
dart run sqflite_common_ffi_web:setup: the first call fails and the console prints "An error occurred while initializing the web worker ... failure to find the worker javascript file at sqflite_sw.js". - Serving the app from a sub path without adjusting
sharedWorkerUri/sqlite3WasmUri, or a server that does not serve.wasmasapplication/wasm. - Upgrading
sqflite_common_ffi_weborsqlite3without re-running setup (--forceif the files look up to date but the wasm version changed). - Using
getDatabasesPath()+joinorpath_provideron the web; use a plain name. - Debugging on changing ports and "losing" the database.
- Passing
singleInstance: falsein shared code (for example for a background task or a second controller): it throws on the web; share the single instance instead. - Setting
databaseFactory = databaseFactoryFfiWebon io (throwsUnsupportedError): guard withkIsWeb. - Importing only
sqflite_ffi_web.dartand expectingDatabaseorOpenDatabaseOptionsto be defined; addpackage:sqflite_common/sqlite_api.dart(orsqflite).
Version History
- aaabf90 Current 2026-09-22 03:38


