mmntjs
Compatibility-first migration bridge away from moment.js

Moment-compatible migration bridge

A safer path away from moment.js.

mmntjs is a compatibility-first replacement for teams that cannot justify a risky date/time rewrite today, but still want a smaller, better-tested path forward.

Recommended: lite (55.2KB raw bundled, moment-compatible)

import moment from "mmntjs/lite";

moment()
  .add(1, "day")
  .format("YYYY-MM-DD");

Also available: fns (standalone functions)

import {
  format,
  startOf,
  add,
} from "mmntjs/fns";

format(
  add(new Date(), 1, "day"),
  "YYYY-MM-DD",
);

Full: moment.js compat (179.5KB raw bundled)

import moment from "mmntjs";

moment
  .utc("2024-01-01")
  .format("YYYY-MM-DD");

Migration tool

# analyze usage
mmntjs migrate --check

# npm alias, zero code change
mmntjs migrate --mode=alias

# auto-choose best target
mmntjs migrate --apply

# force fns
mmntjs migrate --apply --fns

The hard truth

Most teams keep moment.js because replacing it is risky.

Date/time rewrites rarely fail in the obvious paths. They fail in parsing edge cases, invalid-date handling, DST transitions, offsets, and locale behavior that production code has quietly depended on for years.

Quick Start

Start small, then verify.

Evaluate mmntjs in one module, run the tests you already trust, and expand only after checking compatibility-sensitive behavior.

# recommended: lite
# 55.2KB raw bundled, moment-compatible
npm install mmntjs
import moment from "mmntjs/lite";

moment()
  .add(1, "day")
  .format("YYYY-MM-DD");

# or standalone functions (small base)
import {
  format,
  add,
} from "mmntjs/fns";

# or full compat for migration
# 179.5KB raw bundled
import moment from "mmntjs";

moment
  .utc("2024-01-01")
  .format();

Why mmntjs

Compatibility-first

630/630 moment.js 2.30.1 tests pass, verified by oracle tests and fuzzing. The mmntjs CLI automates import rewrites and generates migration reports.

Smaller and faster

A modern TypeScript implementation that is both smaller than moment.js and faster on every tracked operation, without sacrificing compatibility.

Bridge to modern APIs

Adopt incrementally today, then move new code toward Temporal over time rather than via a forced rewrite.

Compatibility Snapshot

Proof should come before persuasion.

Area Status Notes
Formatting Compatible Token and locale output are covered by upstream and locale-derived tests.
Manipulation Compatible add/subtract/startOf/endOf semantics are treated as compatibility-critical.
Query and comparison Compatible diff and comparison methods are covered by oracle and property tests.
Duration Compatible Construction, normalization, and relative-time behavior are part of the test matrix.
Locale Compatible Locale behavior is validated against the upstream locale suite.
UTC and parseZone Compatible UTC and fixed-offset behavior are tested; timezone package provides compatible IANA timezone data support.
Invalid dates Compatible Examples: moment("2024-02-31"), moment("not-a-date"), moment([2024, 1, 31]), and moment.invalid().
Parsing Mostly compatible Standard ISO, RFC 2822, custom format, array, object, sign-prefixed, and control-character inputs match moment.js. One known difference is mixed input like "93280531 09-3911".

Quality

Quality is part of the product surface.

  • 630/630 moment.js 2.30.1 compatibility tests passing
  • Differential oracle tests and property-based comparisons
  • Coverage-guided fuzzing plus grammar-based ISO generation
  • DST and timezone boundary tests across multiple timezones
  • Regression fixtures for previously discovered edge cases
  • TZ-sensitive test runs in UTC and non-UTC environments

Performance

Competitive with date-fns, faster than moment.js.

  • vs moment.js: all 14 tracked operations faster (ISO parsing 23x, diff 13x, format 5-9x)
  • vs date-fns: geometric mean 1.45x across 29 rows (format 24x, diff 40x)
  • vs Temporal: ahead on mutation-heavy paths (diff 14x, add 2x, offset 3.4x)
  • mmntjs/fns: wins or ties every row against date-fns (geometric mean 1.78x)
  • mmntjs/lite: 14.8 KB gzip bundled, smaller than moment.js core

Migration Path

6-phase migration plan

Phase 0

Inventory current moment usage with mmntjs migrate --check. Identify timezone, locale, and parsing hotspots.

Phase 0.5

Optionally set npm alias with mmntjs migrate --mode=alias: zero code change, lets your build tool resolve momentmmntjs at install time.

Phase 1

Run mmntjs migrate --apply to auto-rewrite imports. For full-only codebases, start with mmntjs (full compat). For lite-compatible code, switch directly to mmntjs/lite.

Phase 2

If your code only uses basic formatting/manipulation, mmntjs/fns is an option: standalone functions with tree-shakeable cost. Run mmntjs migrate --apply --fns --dry to preview.

Phase 3

Run compatibility checks and review known differences for the APIs your codebase uses. Compare production-like behavior, especially invalid dates, offsets, and custom parsing.

Phase 4

Replace imports in a low-risk module or service and run the existing test suite. Expand rollout module by module with ownership and rollback clarity.

Phase 5

Use the bridge period to guide new code toward modern date/time APIs, including Temporal where it fits.

FAQ

Answer the objections directly.

  • Why not just use Temporal?
  • Is mmntjs a full replacement for moment.js?
  • Does it include timezone data?
  • Why not dayjs, date-fns, or Luxon?
  • How should we migrate safely?