6.5 KiB
| name | description | metadata | ||
|---|---|---|---|---|
| powersync-js-node | PowerSync Node.js and Electron integration — CLI setup, background sync, ETL pipelines, and Electron renderer/main process split |
|
PowerSync Node.js & Electron
Load this when building a Node.js CLI tool, background sync process, ETL pipeline, or Electron desktop app. Always load
powersync-js.mdfirst.
Node.js-specific integration for the PowerSync JavaScript SDK. Use this reference alongside references/sdks/powersync-js.md when building Node.js CLI tools, background sync processes, ETL pipelines, or Electron desktop apps.
| Resource | Description |
|---|---|
| Node.js SDK Reference | Full SDK documentation for Node.js, consult for details beyond the inline examples. |
| Node SDK API Reference | Full API reference for @powersync/node, consult only when the inline examples don't cover your case. |
Node.js
1. Install
npm install @powersync/node@latest
npm install better-sqlite3 # required peer dependency
TypeScript types for better-sqlite3:
npm install --save-dev @types/better-sqlite3
Key Differences from the Web SDK
| Aspect | @powersync/web |
@powersync/node |
|---|---|---|
| SQLite runtime | WebAssembly (wa-sqlite) | Native (better-sqlite3) |
| Web Workers | Yes — DB runs in a worker by default | No — runs synchronously in the main thread |
| Multi-tab sync | Yes — shared sync worker across browser tabs | No |
| UI framework hooks | @powersync/react, @powersync/vue |
None — use imperative API |
| Environment | Browser | Node.js 18+ |
2. Setup
import { PowerSyncDatabase } from '@powersync/node';
import { AppSchema } from './AppSchema';
import { PowerSyncConnector } from './PowerSyncConnector';
const db = new PowerSyncDatabase({
schema: AppSchema,
database: {
dbFilename: 'app.db'
}
});
const connector = new PowerSyncConnector();
await db.connect(connector);
connect() behaves the same as the web SDK — it starts the sync stream in the background. Use db.waitForFirstSync() to wait for data before proceeding.
Querying
No UI hooks are available in Node.js. Use the imperative API from references/sdks/powersync-js.md directly:
// One-time queries
const lists = await db.getAll('SELECT * FROM lists WHERE owner_id = ?', [userId]);
const list = await db.getOptional('SELECT * FROM lists WHERE id = ?', [id]);
// Watch for changes (async generator)
for await (const result of db.watchWithAsyncGenerator('SELECT * FROM lists')) {
console.log('Lists updated:', result.rows._array);
}
// Writes
await db.execute('INSERT INTO lists (id, name) VALUES (uuid(), ?)', ['My List']);
await db.writeTransaction(async (tx) => {
await tx.execute('DELETE FROM lists WHERE id = ?', [listId]);
await tx.execute('DELETE FROM todos WHERE list_id = ?', [listId]);
});
Use Cases
- CLI tools: Sync data from a PowerSync service for offline-capable scripts
- Background sync jobs: Keep a local SQLite database up to date with server data for reporting or ETL
- Server-side scripts: Read/write to a local PowerSync-managed SQLite database without a browser
Sync Status
The same db.currentStatus and db.registerListener API applies:
db.registerListener({
statusChanged: (status) => {
console.log('Connected:', status.connected, '| Last synced:', status.lastSyncedAt);
}
});
Electron
Electron apps have two distinct environments — the renderer process (a Chromium browser window) and the main process (Node.js). PowerSync has a different SDK for each.
Architecture
Electron App
├── Renderer Process (Chromium)
│ └── Use @powersync/web + @powersync/react or @powersync/vue
│ → See references/sdks/powersync-js-react.md or references/sdks/powersync-js-vue.md
│
└── Main Process (Node.js)
└── Use @powersync/node + better-sqlite3
→ Use imperative API — no UI hooks available
Renderer Process
The renderer process is a full browser environment. Set it up exactly like any other web app:
npm install @powersync/web@latest @journeyapps/wa-sqlite@latest @powersync/react@latest
Use PowerSyncContext.Provider and useQuery/useStatus hooks as documented in references/sdks/powersync-js-react.md. The Web-Specific Options section in references/sdks/powersync-js.md (VFS options, multi-tab, debugMode) also applies to the renderer process.
Main Process
The main process runs Node.js with no DOM. Use @powersync/node:
npm install @powersync/node@latest better-sqlite3
// main/db.ts
import { PowerSyncDatabase } from '@powersync/node';
import { AppSchema } from './AppSchema';
import { PowerSyncConnector } from './PowerSyncConnector';
export const db = new PowerSyncDatabase({
schema: AppSchema,
database: { dbFilename: 'app.db' }
});
export async function initDb() {
const connector = new PowerSyncConnector();
await db.connect(connector);
await db.waitForFirstSync();
}
IPC Pattern
If you sync data in the main process and need to expose it to the renderer, use Electron's IPC:
// main/ipcHandlers.ts
import { ipcMain } from 'electron';
import { db } from './db';
ipcMain.handle('powersync:query', async (_event, sql: string, params: any[]) => {
return db.getAll(sql, params);
});
// renderer — via preload bridge
const lists = await window.electron.invoke('powersync:query', 'SELECT * FROM lists', []);
However, the more common pattern is to use @powersync/web in the renderer and maintain a separate sync connection there — this keeps the data layer entirely in the renderer process and avoids IPC overhead.
Common Pitfalls
Using @powersync/web in Node.js
@powersync/web requires browser APIs (SharedWorker, indexedDB, WebAssembly with browser globals) that are not available in Node.js. Always use @powersync/node for the main process or any non-browser Node.js environment.
Missing better-sqlite3 native build
better-sqlite3 is a native module that must be compiled for the target platform. In Electron, it must be rebuilt for Electron's Node.js version using electron-rebuild or @electron/rebuild:
npx @electron/rebuild -f -w better-sqlite3
Run this after any Electron version upgrade.