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

mongoshift

v0.1.0

Published

MongoDB migration tool with dry-run, file-hash detection, and stored logs

Readme

mongoshift

A MongoDB migration tool with dry-run, file-hash drift detection, stored logs, and first-class TypeScript support.

Highlights

  • Dry-run via up({ dryRun: true }) and --dry-run CLI flag
  • Stored logs: every migration's ctx.logger output is persisted inline in the changelog entry (level, message, timestamp, duration)
  • Optional file-hash drift detection (useFileHash: true) — refuses to run if an applied migration's file has changed
  • Configurable changelog collection name, timestamp dateFormat, custom migration templates (--template or sample-migration.ts)
  • TS-native single package, compiled to ESM + .d.ts
  • Node 24+, ESM only

Install

npm  install mongoshift mongodb
pnpm add     mongoshift mongodb
yarn add     mongoshift mongodb
bun  add     mongoshift mongodb

Quick start

npx mongoshift init                 # creates mongoshift.config.ts + migrations/
npx mongoshift create "add users"   # creates 20260405090703-add_users.ts
npx mongoshift up                   # applies all pending
npx mongoshift status               # shows PENDING / APPLIED / CHANGED
npx mongoshift down                 # rolls back the last one

A migration file looks like this:

import type { Db, MongoClient } from "mongodb";
import type { MigrationContext } from "mongoshift";

export const up = async (db: Db, client: MongoClient, ctx: MigrationContext) => {
  ctx.logger.log("creating users collection");
  if (ctx.dryRun) return; // optional: skip side-effects when dry-running
  await db.createCollection("users");
};

export const down = async (db: Db, client: MongoClient, ctx: MigrationContext) => {
  await db.collection("users").drop();
};

Programmatic API

import { loadConfig, connect, up, down, status } from "mongoshift";

const config = await loadConfig();
const { db, client, close } = await connect(config);
try {
  const result = await up(db, client, config, { dryRun: true });
  // result.migrations: [{ fileName, logs, durationMs, applied }]
} finally {
  await close();
}

Config reference (short)

// mongoshift.config.ts
import type { Config } from "mongoshift";

const config: Config = {
  mongodb: { url: "mongodb://localhost:27017", databaseName: "my_db" },
  migrationsDir: "migrations",
  migrationFileExtension: ".ts",
  dateFormat: "YYYYMMDDHHmmss", // dayjs tokens (wrap literals in [brackets])
  changelogCollectionName: "changelog",
  useFileHash: false,
};
export default config;

Migrating from migrate-mongo

mongoshift is API-compatible in spirit but has a few deliberate breaks.

1. Config file

| migrate-mongo | mongoshift | | ------------------------------- | --------------------------------------------- | | migrate-mongo-config.js | mongoshift.config.ts (or .js) | | CommonJS by default | ESM only | | moduleSystem: "commonjs" | removed (ESM only) | | lockCollectionName, lockTtl | removed (for now) | | no dateFormat | dateFormat: "YYYYMMDDHHmmss" (configurable) |

Everything else maps 1:1: mongodb, migrationsDir, migrationFileExtension, changelogCollectionName, useFileHash.

2. Migration signature — breaking change

migrate-mongo:

export const up = async (db, client) => {
  /* ... */
};

mongoshift adds a third ctx argument:

export const up = async (db, client, ctx) => {
  ctx.logger.log("..."); // persisted in changelog
  if (ctx.dryRun) return; // respect dry-run
};

Old migrations that ignore the 3rd parameter keep working unchanged — the logger and dryRun flag are simply unused. You only need to touch your files if you want to use those features.

3. CLI command mapping

| migrate-mongo | mongoshift | | ----------------------------- | ------------------------------------------ | | migrate-mongo init | mongoshift init | | migrate-mongo create <name> | mongoshift create <name> [-t template] | | migrate-mongo up | mongoshift up [--dry-run] [--force-hash] | | migrate-mongo down | mongoshift down [--dry-run] [--block] | | migrate-mongo status | mongoshift status |

4. Keeping existing changelog entries

The changelog schema is a superset: existing migrate-mongo documents ({ fileName, appliedAt, migrationBlock, fileHash? }) are read correctly. New fields (logs: [], durationMs) are added as new migrations run. You can switch without dropping the collection.

If you want to backfill the new fields on old entries for consistency, run once:

await db
  .collection("changelog")
  .updateMany({ logs: { $exists: false } }, { $set: { logs: [], durationMs: 0 } });

5. Dropped features (for now)

  • Locks (lockCollectionName / lockTtl) — planned; use an external lock for now if you run concurrent deploys.
  • CJS support — ESM only.

Coming from other tools

  • umzug (generic, covers MongoDB): umzug's storage is storage-agnostic; here the storage is always the configured MongoDB changelogCollectionName. Replace your up/down signature with (db, client, ctx).
  • node-migrate: state is stored in a .json file on disk; switch to a MongoDB collection via changelogCollectionName. Migration files become async ESM modules.
  • Custom scripts in scripts/migrate.ts: port them 1-to-1, they just become the bodies of up() / down().

Roadmap

  • Distributed lock (TTL-based, configurable)
  • Website with full API docs, guides, recipes
  • Transactions helper for multi-statement migrations

License

MIT