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

@vibeorm/migrate

v5.0.2

Published

Migration engine for VibeORM v2 — IR differ, per-dialect DDL, migration runner, introspection

Readme

@vibeorm/migrate

Part of VibeORM — a type-safe TypeScript ORM for Bun and Node. Prisma-schema or TypeScript-DSL input, a canonical schema IR, a generated client, and a dialect-aware SQL layer over PostgreSQL, PGlite, SQLite and MySQL.

The migration engine: it diffs two schema IRs into dialect-neutral steps, renders those steps as per-dialect DDL, applies them with bookkeeping, and introspects a live database back into IR. It is its own package so that the CLI and tests can run schema changes without pulling in the query runtime, and so every SQL-text decision stays in one reviewable place.

bun add @vibeorm/migrate

Stable. 2.0.0, published under the latest dist-tag. The v1 line stays installable as vibeorm@1.

Most users never install this directly — it ships as a dependency of vibeorm and of the generated client. Reach for it when you are writing an adapter or tooling against the runtime.

What it does

Three stages, each usable on its own.

Diff. diffSchemas({ from, to, dialect }) returns ordered MigrationStep values — createTable, addColumn, alterColumn, createIndex, addForeignKey, createJoinTable, dropView and the rest. Steps carry IR fragments, never SQL text, and are emitted in dependency-safe order. Both sides normalize before comparison, so diffSchemas({ from: introspect(push(X)), to: X }) is empty: pushing twice is a no-op. There is no rename detection — a renamed table diffs as drop plus create.

Render. renderSteps({ steps, dialect, from, to }) produces the SQL strings for postgres, sqlite (including the table-rebuild recipe for ALTERs sqlite cannot express) or mysql. describeStep({ step }) gives the one-line human description used in CLI output and refusal messages.

Run. applyMigrations executes MigrationFiles in order under an advisory lock, recording each in the _vibe_migrations bookkeeping table with a sha256 checksum over its statements. Re-applying a migration whose SQL changed is a VIBE_MIGRATION error, not a silent divergence. On postgres and sqlite each migration runs inside one transaction with its bookkeeping row; on mysql, where DDL auto-commits, progress is recorded per statement and a re-run resumes from where it stopped. migrationStatus reports applied, pending, mismatched and mid-rollback migrations, rollbackMigration runs a migration's downSql, and resolveMigration repairs the bookkeeping table without running SQL.

Introspect. introspectPostgres, introspectSqlite and introspectMysql read a live database back into SchemaIR; pull picks the right one for a dialect.

push vs migrate

push goes straight from the live database to your schema — introspect, diff, render, apply — with no files kept. It suits prototyping and disposable databases. generateMigration plus applyMigrations keeps named, checksummed SQL files you can review and replay, which is what shared and production databases need. Details in docs/migrations.md.

Destructive steps

Every step carries a destructive flag: drops of tables, columns, enums and join tables, plus narrowing type changes. push refuses to run when any step is destructive unless you pass acceptDataLoss: true, and the thrown VibeError (VIBE_MIGRATION) lists each offending step by description. generateMigration surfaces the same information as MigrationFile.destructive so callers can require confirmation before applying. Constructs a dialect cannot express — scalar lists on sqlite and mysql, partial indexes on mysql, removing a value from a surviving enum — throw VIBE_UNSUPPORTED_CAPABILITY instead of degrading.

Usage

import { applyMigrations, generateMigration, push, pull } from "@vibeorm/migrate";
import { toSqlExecutor } from "@vibeorm/runtime";

const executor = toSqlExecutor({ adapter });

// Prototyping: make the database match the schema.
const result = await push({ executor, schema, acceptDataLoss: false });
console.log(result.steps, result.applied);

// Versioned: render a named migration from a diff, then apply it.
const migration = generateMigration({ from: previous, to: schema, name: "add_posts", dialect: "postgres" });
await applyMigrations({ executor, migrations: [migration], dialect: "postgres" });

// Introspect the live database back into IR.
const live = await pull({ executor, dialect: "postgres" });

Objects another tool owns are declared as plain ExternalObjectOwner data. parseExternalObjects validates declarations without a database, inspectExternalObjects({ executor, dialect, external }) resolves them against the catalog, and push accepts that resolution as external; applyMigrations takes the plain declarations as external and resolves them under its lock. PostgreSQL and PGlite only. See external objects.

SqlExecutor calls must all reach the same database session — the engine issues BEGIN/COMMIT, PRAGMA and advisory-lock statements through it. Pool-backed executors must pin one connection for the whole operation.

Links