npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@facetlayer/sqlite-migration

v0.1.0

Published

SQLite schema migration library for detecting and applying schema drifts.

Readme

@facetlayer/sqlite-migration

SQLite schema migration library for detecting and applying schema drifts.

Features

  • Detect schema differences between your database and target schema
  • Apply safe migrations (add tables, add nullable columns, create indexes)
  • Apply destructive migrations (drop extra tables)
  • Retry support for concurrent migration handling
  • Works with any SQLite wrapper via the TargetDatabase interface

Installation

npm install @facetlayer/sqlite-migration

Quick Start

import { applyMigration, TargetDatabase, DatabaseSchema } from '@facetlayer/sqlite-migration';

// Implement the TargetDatabase interface for your SQLite wrapper
const db: TargetDatabase = {
  get: async (sql, ...params) => /* execute query, return first row */,
  list: async (sql, ...params) => /* execute query, return all rows */,
  run: async (sql, ...params) => /* execute statement */,
  pragma: async (statement) => /* execute pragma */,
  info: (msg) => console.log(msg),
  warn: (msg) => console.warn(msg),
};

// Define your target schema
const schema: DatabaseSchema = {
  name: 'my-app',
  statements: [
    'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)',
    'CREATE TABLE posts (id INTEGER PRIMARY KEY, user_id INTEGER, title TEXT)',
    'CREATE INDEX idx_posts_user_id ON posts(user_id)',
  ],
};

// Apply migrations (safe mode - won't drop tables or columns)
await applyMigration(db, schema, 'safe-updates');

// Or apply all migrations including destructive ones
await applyMigration(db, schema, 'destructive-updates');

API

applyMigration(db, schema, migrationType)

High-level function that detects drifts and applies migrations with retry support for concurrent access.

await applyMigration(db, schema, 'safe-updates');      // Safe migrations only
await applyMigration(db, schema, 'destructive-updates'); // All migrations

Parameters:

  • db: TargetDatabase - Database interface implementation
  • schema: DatabaseSchema - Target schema definition
  • migrationType: MigrationType - Either 'safe-updates' or 'destructive-updates'

findDatabaseDrift(db, schema)

Analyzes the database and returns all drifts needed to match the target schema. Use this when you want to inspect what changes will be made before applying them.

import { findDatabaseDrift, DatabaseSchema } from '@facetlayer/sqlite-migration';

const schema: DatabaseSchema = {
  name: 'my-app',
  statements: [
    'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, email TEXT)',
    'CREATE INDEX idx_users_email ON users(email)',
  ],
};

const drift = await findDatabaseDrift(db, schema);

// Inspect drifts by table
for (const [tableName, tableDrift] of drift.tables.entries()) {
  console.log(`Table: ${tableName}`);
  for (const d of tableDrift.drifts) {
    console.log(`  - ${d.type}`, d.columnName || d.indexName || '');
  }
}

// Check warnings
for (const warning of drift.warnings) {
  console.warn(warning);
}

Returns: Promise<DatabaseDrift>

The DatabaseDrift object contains:

  • tables: Map<string, TableDrift> - Drifts organized by table name
  • warnings: string[] - Warnings about extra tables or unsupported changes

generateSafeMigration(dbDrift, schema)

Generates SQL statements for safe, non-destructive migrations only.

import { findDatabaseDrift, generateSafeMigration } from '@facetlayer/sqlite-migration';

const drift = await findDatabaseDrift(db, schema);
const result = generateSafeMigration(drift, schema);

console.log('Statements to execute:', result.statements);
console.log('Skipped (destructive):', result.warnings);

Safe operations include:

  • Creating new tables
  • Adding nullable columns
  • Creating new indexes

generateDestructiveUpdates(dbDrift, schema)

Generates SQL statements for all migrations, including destructive ones.

import { findDatabaseDrift, generateDestructiveUpdates } from '@facetlayer/sqlite-migration';

const drift = await findDatabaseDrift(db, schema);
const result = generateDestructiveUpdates(drift, schema);

console.log('Statements to execute:', result.statements);
console.log('Unsupported operations:', result.warnings);

Destructive operations include:

  • Everything in safe migrations
  • Dropping extra tables

Note: Table rebuilds and column drops are not yet supported and will generate warnings.

Types

TargetDatabase

Interface for database operations. All database methods return Promises to support async SQLite wrappers.

interface TargetDatabase {
  get(sql: string, ...params: any[]): Promise<Record<string, any> | undefined>;
  list(sql: string, ...params: any[]): Promise<Record<string, any>[]>;
  run(sql: string, ...params: any[]): Promise<void>;
  pragma(statement: string): Promise<void>;
  info(msg: string): void;
  warn(msg: string): void;
}

DatabaseSchema

interface DatabaseSchema {
  name: string;           // Schema identifier
  statements: string[];   // CREATE TABLE and CREATE INDEX statements
}

DriftType

type DriftType =
  | 'need_to_create_table'
  | 'need_to_add_column'
  | 'need_to_delete_column'
  | 'need_to_modify_column'
  | 'need_to_rebuild_table'
  | 'need_to_create_index'
  | 'need_to_delete_index'
  | 'extra_table';

Example: Using with better-sqlite3

import Database from 'better-sqlite3';
import { applyMigration, TargetDatabase, DatabaseSchema } from '@facetlayer/sqlite-migration';

const sqliteDb = new Database('app.db');

const db: TargetDatabase = {
  get: async (sql, ...params) => sqliteDb.prepare(sql).get(...params),
  list: async (sql, ...params) => sqliteDb.prepare(sql).all(...params),
  run: async (sql, ...params) => { sqliteDb.prepare(sql).run(...params); },
  pragma: async (statement) => { sqliteDb.pragma(statement, { simple: true }); },
  info: (msg) => console.log('[migration]', msg),
  warn: (msg) => console.warn('[migration]', msg),
};

const schema: DatabaseSchema = {
  name: 'my-app',
  statements: [
    'CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)',
  ],
};

await applyMigration(db, schema, 'safe-updates');

Example: Inspecting Drifts Before Applying

import { findDatabaseDrift, generateSafeMigration } from '@facetlayer/sqlite-migration';

// Find what needs to change
const drift = await findDatabaseDrift(db, schema);

// Preview the SQL that will be executed
const { statements, warnings } = generateSafeMigration(drift, schema);

console.log('Will execute:');
statements.forEach(sql => console.log(`  ${sql}`));

console.log('Will skip (destructive):');
warnings.forEach(w => console.log(`  ${w}`));

// Now apply if satisfied
await applyMigration(db, schema, 'safe-updates');