Electron + Drizzle + SQLite: Skip the Native Addon Hell, Use node:sqlite
Electron apps that need a local database can now skip the entire `better-sqlite3` → `electron-rebuild` → ASAR unpack pipeline. The built-in `node:sqlite` driver works today, but the Vite bundler and Forge packager will silently break module resolution and file paths unless three specific config fixes are applied.
The combination of Electron Forge, Vite, and Drizzle ORM hits two distinct failure modes when connecting to SQLite. First, Vite treats Node's built-in `node:sqlite` module as a browser external, so `DatabaseSync` disappears from the bundle unless the module is explicitly listed in Rollup's `external` config. Second, and more insidious, the migration folder path resolves to `/drizzle` — the OS root — because `__dirname` inside a Vite-bundled main process no longer points to the project source tree.
Switching to `better-sqlite3` only trades one problem for a longer chain: dynamic `.node` require failures in the Vite bundle, missing modules after `electron-forge make`, and the realization that `@electron-forge/plugin-auto-unpack-natives` handles ASAR unpacking but does not copy the entire npm package into the final app. The built-in `node:sqlite` driver sidesteps all of this — no native addon, no `electron-rebuild`, no ABI mismatches.
The remaining fixes are straightforward: mark `node:sqlite` as external in the Vite config, use `app.getAppPath()` in development and `process.resourcesPath` in production to locate migrations, ship the `drizzle/` folder via Forge's `extraResource`, and store the SQLite database file in `app.getPath('userData')` rather than a relative path or the Documents folder.
The `node:sqlite` built-in module has reached the point where it eliminates the most painful part of Electron database setup — the native addon rebuild chain — yet most Electron + SQLite guides still default to `better-sqlite3` out of habit.
Vite's `external` config solves the bundling problem but creates a packaging problem Forge doesn't automatically handle; the `auto-unpack-natives` plugin name is misleading because it unpacks files already present, rather than ensuring external dependencies are present in the first place.
The migration path bug (`/drizzle`) is a concrete example of how Vite's bundling silently relocates `__dirname`, making relative-path assumptions from Node.js tutorials actively dangerous in bundled Electron main processes.
Separating migration files (shipped as app resources) from the database file (stored in user data) is the correct architecture, but Forge's `extraResource` and Electron's `process.resourcesPath` are the only reliable way to make that separation survive packaging.