
Security News
Feross on TBPN: How North Korea Hijacked Axios
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.
A lightweight SQLite migration system for Node.js, built with TypeScript. Manage your SQLite database schema changes with ease and confidence.
npm install sqlite-up better-sqlite3
# or
yarn add sqlite-up better-sqlite3
# or
pnpm add sqlite-up better-sqlite3
mkdir migrations
migrations/001_create_users.ts:import { Database } from 'better-sqlite3';
export const up = (db: Database): void => {
db.exec(`
CREATE TABLE users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT NOT NULL UNIQUE,
name TEXT NOT NULL,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
)
`);
};
export const down = (db: Database): void => {
db.exec('DROP TABLE users');
};
import { Database } from 'better-sqlite3';
import { Migrator } from 'sqlite-up';
async function main() {
const db = new Database('myapp.db');
const migrator = new Migrator({
db,
migrationsDir: './migrations',
});
// Run all pending migrations
const result = await migrator.apply();
if (result.success) {
console.log('Applied migrations:', result.appliedMigrations);
} else {
console.error('Migration failed:', result.error);
}
}
main().catch(console.error);
MigratorThe main class for managing migrations.
interface MigratorOptions {
db: Database; // better-sqlite3 database instance
migrationsDir: string; // Directory containing migration files
migrationsTable?: string; // Optional: Table name for tracking migrations (default: 'schema_migrations')
migrationsLockTable?: string; // Optional: Table name for migration locks (default: 'schema_migrations_lock')
fileExtensions?: string[]; // Optional: File extensions to look for (default: ['ts', 'js']). Note: .d.ts files are always ignored
}
apply()Apply all pending migrations.
const migrator = new Migrator({
db,
migrationsDir: './migrations',
});
// Run all pending migrations
const result = await migrator.apply();
if (result.success) {
console.log('Applied migrations:', result.appliedMigrations);
} else {
console.error('Migration failed:', result.error);
}
rollback()Rollback the most recent batch of migrations.
// Rollback the last batch of migrations
const result = await migrator.rollback();
if (result.success) {
console.log('Rolled back:', result.appliedMigrations);
} else {
console.error('Rollback failed:', result.error);
}
status()Get the status of all migrations. Shows which migrations have been applied and which are pending.
const status = await migrator.status();
console.log('Migration Status:', status);
// Example output:
// Migration Status: {
// currentBatch: 1,
// pending: 0,
// applied: [
// {
// name: '001_users_table.ts',
// executed_at: '2025-01-22T12:29:22.402Z',
// batch: 1
// },
// {
// name: '002_add_age.ts',
// executed_at: '2025-01-22T12:29:22.406Z',
// batch: 1
// }
// ]
// }
plan()Plan the pending migrations without applying them. Returns the next batch number and the list of pending migration names in order.
const plan = await migrator.plan();
console.log('Migration Plan:', plan);
// Example output:
// Migration Plan: {
// nextBatch: 2,
// pending: ['003_add_email_index.ts']
// }
The migrator extends EventEmitter and emits events during migration:
// Listen for migration events
migrator.on('migration:applied', function (name: string, batch: number): void {
console.log(`✅ Migration Applied: "${name}" in batch ${batch}`);
});
migrator.on('migration:rollback', function (name: string, batch: number): void {
console.log(`🔄 Migration Rolled Back: "${name}" from batch ${batch}`);
});
// Run migrations after setting up listeners
await migrator.apply();
All migrations are run within a transaction. If any part of a migration fails, the entire migration is rolled back:
export const up = (db: Database): void => {
// Both operations will be in the same transaction
db.exec('CREATE TABLE users (id INTEGER PRIMARY KEY)');
db.exec('CREATE INDEX idx_user_id ON users(id)');
// If any operation fails, the entire migration is rolled back
// and the database remains in its previous state
};
Migration files should be TypeScript or JavaScript files that export up and down functions:
import { Database } from 'better-sqlite3';
export const up = (db: Database): void => {
// Migration code here
};
export const down = (db: Database): void => {
// Rollback code here
};
Files should be named using the format: XXX_description.ts where XXX is a sequence number (e.g., 001_, 002_).
import {
SqliteUpError, // Base error class
MigrationFileError, // Issues with migration files
MigrationLockError, // Locking-related errors
MigrationExecutionError, // Errors during migration execution
} from 'sqlite-up';
try {
await migrator.apply();
} catch (error) {
if (error instanceof MigrationLockError) {
console.error('Migration failed, a different process is holding the lock:', error.message);
}
}
The library provides specific error classes for different scenarios:
MigrationError - Base error classMigrationFileError - Issues with migration filesMigrationExecutionError - Errors during migration executionMigrationLockError - Lock-related errorsCheck out the example directory for complete working examples.
This happens due to how module resolution works in Vitest. To work around this, you can add a setupFile to your vitest.setup.ts file:
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
reporters: ['verbose'],
include: ['src/**/*.test.ts'],
coverage: {
reporter: ['text', 'json', 'html'],
},
setupFiles: ['./vitest.setup.ts'],
},
});
Then in your vitest.setup.ts file, register the TypeScript loader:
import { register } from 'node:module';
import { pathToFileURL } from 'node:url';
// Register TypeScript loader
register('ts-node/esm', pathToFileURL('./'));
// This will ensure .ts files are properly loaded
process.env.NODE_OPTIONS = '--loader ts-node/esm';
# Install dependencies
pnpm install
# Run tests
pnpm test
# Run tests with coverage
pnpm test:coverage
# Build the project
pnpm build
# Lint the code
pnpm lint
# Format the code
pnpm format
This project is licensed under the MIT License - see the LICENSE file for details.
FAQs
A lightweight SQLite migration system for Node.js
The npm package sqlite-up receives a total of 3 weekly downloads. As such, sqlite-up popularity was classified as not popular.
We found that sqlite-up demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Socket CEO Feross Aboukhadijeh breaks down how North Korea hijacked Axios and what it means for the future of software supply chain security.

Security News
OpenSSF has issued a high-severity advisory warning open source developers of an active Slack-based campaign using impersonation to deliver malware.

Research
/Security News
Malicious packages published to npm, PyPI, Go Modules, crates.io, and Packagist impersonate developer tooling to fetch staged malware, steal credentials and wallets, and enable remote access.