You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Web: option to run sync on the main isolate (disable the shared sync worker) for reload-based crash recovery #459
On Flutter web the sync engine runs inside a shared worker (WebPowerSyncDatabase.connectInternal → SyncWorkerHandle.start → new SharedWorker(workerUri) in lib/src/web/sync_controller.dart). That shared worker is deliberately kept alive across DB close (lib/src/web/worker.dart — "The worker is also used for sync … we shouldn't close it just because a database has been closed") and persists across a full page reload.
The downside: if the sync isolate inside that shared worker ever wedges or crashes, a plain page reload does not recover it — the reloaded page reconnects to the same (still-dead) shared worker, and any other open tab of the origin keeps it alive regardless. The only recoveries are to close every tab of the origin (so the browser GCs the now-zero-client worker) or to terminate the worker via chrome://inspect. For a single-user PWA this is a real papercut: sync silently stops and the obvious user action (reload) doesn't fix it.
Notably, connectInternalalready contains a main-isolate fallback — it constructs a StreamingSyncImplementation (no shared worker) in the catch branch — but that branch is only reached if SyncWorkerHandle.start throws, which in practice only happens for a blob: workerUri behind an assert (i.e. debug/test only). There is no supported way to opt into it in a release build.
Proposed solution
Expose an option — e.g. a field on SyncOptions, or a parameter to connect(...) — to run sync on the main isolate instead of the shared sync worker, i.e. deterministically take the existing StreamingSyncImplementation path.
Benefits:
A plain page reload (or an app-coordinated all-tabs reload) reliably restarts sync, because nothing survives the reload.
Single-user PWAs that don't need cross-tab sync coordination can trade that for crash-recoverability.
The database can keep running in its own (dedicated or shared) worker independently — this request is specifically about the sync worker.
Alternatives considered
Overriding WebPowerSyncOpenFactory.connectToWorker — only controls the database worker's AccessMode (via sqlite3_web). The sync worker is spawned by a separatenew SharedWorker(workerUri) call that never consults the factory, so moving the DB to a dedicated worker does not move sync off the shared worker (verified empirically — the DB-dedicated build still spawns a shared *_db.worker.js for sync).
Forking the SDK to skip SyncWorkerHandle.start — works, but is an ongoing maintenance burden on the most correctness-sensitive layer.
Environment
powersync 2.3.1 (also checked latest 2.3.3 — no such option); sqlite3_web 0.9.2; sqlite_async 0.14.3.
: if the sync isolate inside that shared worker ever wedges or crashes, a plain page reload does not recover it
If only a single tab of your app is open, reloading that tab will also restart the shared worker on all major browsers. You mention this could be useful for "Single-user PWAs that don't need cross-tab sync coordination", which is a fair point but then you already get the behavior you're interested in.
I'm not opposed to that option, but if there's more than one tab then one of them attempting to connect would wait for sync locks all the time which is also not great if wedges/crashes are what you're trying to avoid.
It would be good to understand the full motivation behind this request: Are you seeing broken shared workers? If so, that's something we should fix! If you have ways to reproduce that, we would love to take a look.
Activity
simolus3 commentedon Aug 18, 2026
If only a single tab of your app is open, reloading that tab will also restart the shared worker on all major browsers. You mention this could be useful for "Single-user PWAs that don't need cross-tab sync coordination", which is a fair point but then you already get the behavior you're interested in.
I'm not opposed to that option, but if there's more than one tab then one of them attempting to connect would wait for sync locks all the time which is also not great if wedges/crashes are what you're trying to avoid.
It would be good to understand the full motivation behind this request: Are you seeing broken shared workers? If so, that's something we should fix! If you have ways to reproduce that, we would love to take a look.