Git Versioned SQLite VFS
git-sqlite-vfs (version 0.0.20) provides a unique solution for versioning SQLite databases using Git. It achieves this by implementing a custom Virtual File System (VFS) extension for SQLite, sharding database files into deterministic 4KB binary pages stored in a specified directory (e.g., `.my-db`). This approach resolves the common issue of binary merge conflicts in Git when trying to version a monolithic SQLite database file, enabling effective diffing and merging of database changes. The library integrates seamlessly with popular tools like Drizzle ORM and libSQL clients, and is compatible with both Node.js (v22.5+) and Deno environments. While still in early development, it offers CLI tools to replace standard `drizzle-kit` commands for schema management and migrations within the VFS context, ensuring database changes are correctly applied to the sharded structure. Its primary differentiator is making SQLite a first-class citizen in Git-based version control workflows, enabling collaborative database schema and data evolution.
Common errors
-
Error: VFS extension not loaded
cause Attempting to use `git-sqlite-vfs` functionality in Deno without correctly loading the native VFS extension, often due to importing the browser-compatible `@libsql/client`.fixUse `createVFSClient` from `git-sqlite-vfs` or explicitly import the Node-specific `@libsql/client/node` binding in Deno: `import { createClient } from 'npm:@libsql/client@<version>/node';` -
Database file size not shrinking; unused '.bin' files accumulating in VFS directory.
cause The SQLite database is not configured for full auto-vacuuming or delete journaling, preventing the VFS from actively removing unused data shards.fixEnsure `PRAGMA auto_vacuum = FULL;` and `PRAGMA journal_mode = DELETE;` are executed upon database connection. Alternatively, run `VACUUM;` periodically to compact the database and allow the VFS to remove out-of-bounds shards. -
Drizzle migrations/schema push not reflecting changes in VFS-enabled database.
cause Using `drizzle-kit` commands directly instead of the `git-sqlite-vfs` CLI wrappers, which bypasses the VFS integration.fixAlways use the `git-sqlite-vfs` CLI for schema management: `npx git-sqlite-vfs generate`, `npx git-sqlite-vfs push`, and `npx git-sqlite-vfs migrate`.
Warnings
- breaking The `git-sqlite-vfs` CLI commands (`setup`, `generate`, `push`, `migrate`) are designed to replace their `drizzle-kit` counterparts when working with a VFS-enabled database. Using raw `drizzle-kit` commands directly will not correctly interact with the sharded VFS database and can lead to inconsistencies or lost changes.
- gotcha When using `git-sqlite-vfs` in Deno, importing `@libsql/client` directly (e.g., `import { createClient } from 'npm:@libsql/client';`) will resolve to the browser-compatible implementation, which bypasses the native C extension required for the VFS. This will prevent the VFS from functioning.
- gotcha For efficient database compaction and removal of unused VFS `.bin` shards (e.g., after deletes), SQLite requires `PRAGMA auto_vacuum = FULL;` and `PRAGMA journal_mode = DELETE;`. While `createVFSClient()` automatically sets these upon connection, manual client initialization requires you to run these PRAGMAs explicitly.
- gotcha Node.js compatibility notes: The package leverages Node.js v22.5+ for the internal `node:sqlite` API. For older Node.js versions, it will fall back to using `better-sqlite3`. While generally transparent, this might have implications for performance or specific platform environments.
Install
-
npm install git-sqlite-vfs -
yarn add git-sqlite-vfs -
pnpm add git-sqlite-vfs
Imports
- createVFSClient
const { createVFSClient } = require('git-sqlite-vfs');import { createVFSClient } from 'git-sqlite-vfs'; - drizzle
import { drizzle } from 'drizzle-orm/libsql'; - createClient
import { createClient } from 'npm:@libsql/client';import { createClient } from 'npm:@libsql/client@0.14.0/node';
Quickstart
import { createVFSClient } from 'git-sqlite-vfs';
import { drizzle } from 'drizzle-orm/libsql';
import { sql } from 'drizzle-orm';
const run = async () => {
// Initialize the VFS-enabled client, automatically loading the VFS extension
// and configuring PRAGMAs for compaction.
const client = await createVFSClient({
url: 'file:.db/main.db' // Database path within the VFS sharded directory
});
// Integrate the VFS client with Drizzle ORM
const db = drizzle(client);
// Example: Create a table and insert data using Drizzle
await db.execute(sql`CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT);`);
await db.execute(sql`INSERT INTO users (name) VALUES ('Alice'), ('Bob');`);
const result = await db.execute(sql`SELECT * FROM users;`);
console.log('Users:', result);
// To ensure VFS shards are compacted, trigger a VACUUM periodically
// or rely on auto_vacuum=FULL; and journal_mode=DELETE; which createVFSClient sets.
// await db.execute(sql`VACUUM;`);
await client.close();
};
run().catch(console.error);