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

anchordb

v1.3.2

Published

MongoDB + Mongoose for mobile apps. Offline-first local database with optional sync.

Readme

anchordb

MongoDB + Mongoose, for mobile apps. A local, persistent document database with a Mongoose-shaped API that works completely offline — and optionally synchronises with a backend.

Overview · Report a bug or get support

npm install anchordb

Quick start — no backend required

import { AnchorDB, Schema } from "anchordb";

const db = new AnchorDB({ name: "my-app" });   // no sync block → purely local

const userSchema = new Schema({
  name:  { type: String, required: true, trim: true },
  email: { type: String, required: true, unique: true, lowercase: true },
  age:   { type: Number, min: 0, max: 150 },
  role:  { type: String, enum: ["admin", "user"], default: "user" },
}, { timestamps: true });

const User = db.model("User", userSchema);

await User.create({ name: "Nisala", age: 28, email: "[email protected]" });

const adults = await User.find({ age: { $gte: 18 } })
  .sort("-createdAt")
  .limit(10);

That is Mongoose code. It runs on a phone, offline, with no server anywhere.

Two principles

1. Zero re-learning. If you know MongoDB and Mongoose on the backend, you already know this: the same Schema, model(), query builder, populate, ObjectId, index options and error codes (err.code === 11000, err.errors[path].kind). Anything Mongoose does that AnchorDB does not is written down, never silently reinterpreted.

2. Sync is optional. An app with no backend is the default case, not a degraded one. With no sync block there is no mutation queue, no network code, no sync metadata and no tombstones. Adding sync later requires no changes to your CRUD code.

Decorators (optional)

Identical in shape to @nestjs/mongoose, so the same decorated class can be shared between an Ionic/Angular app and a NestJS backend:

import { Schema, Prop, SchemaFactory } from "anchordb/decorators";

@Schema({ timestamps: true })
export class User {
  @Prop({ required: true }) name!: string;
  @Prop(String) nickname!: string;
  @Prop([String]) tags!: string[];
}
export const UserSchema = SchemaFactory.createForClass(User);

Requires experimentalDecorators + emitDecoratorMetadata for type inference — or pass the type explicitly (@Prop(String)) and no metadata is needed at all.

Storage adapters

| Adapter | Import | Platform | Verified here | | --- | --- | --- | --- | | Memory | MemoryAdapter from anchordb | any | yes — conformance suite | | Node SQLite | anchordb/storage/node-sqlite | Node 22.5+ (built in, no native deps) | yes — conformance suite | | IndexedDB | anchordb/storage/indexeddb | browser, PWA, ionic serve | yes — conformance suite | | Expo SQLite | anchordb/storage/expo-sqlite | React Native, iOS/Android | no — see below | | Capacitor SQLite | anchordb/storage/capacitor-sqlite | Ionic native | no — see below |

All adapters sit behind one DatabaseAdapter interface, and the three verified ones are held to a single 70-test conformance suite, so unique-index semantics, null handling and write atomicity cannot drift between them.

Interchange with MongoDB

Export and import speak what mongoexport writes and mongoimport reads, in both directions and in both formats:

// Extended JSON — lossless. NDJSON by default, which mongoimport reads with no extra flag.
const file = await Model.export({ mode: "canonical" });

// Only what a filter matches, run as a real query so it is cast and indexed like any other.
const page = await Model.export({ filter: { status: "active" } });

// CSV — for spreadsheets, and for mongoimport --type=csv --headerline.
const csv = await Model.export({ format: "csv" });

// Import auto-detects a JSON array, NDJSON or CSV.
await db.import(text, { mode: "upsert" });

mongoimportCommand() prints the exact command that ingests the result.

CSV carries no types, so on import values are inferred conservatively and then cast through the collection's schema — a declared Number comes back a number rather than the text the file held. Two things CSV genuinely cannot round-trip, stated rather than hidden: null and a missing field are both an empty cell (read back as missing, matching mongoimport --ignoreBlanks), and nested fields travel as dotted paths.

Extended JSON has three modes, matching the ones MongoDB Compass offers: canonical (lossless), relaxed (readable), and default (relaxed, except integers past 2^53 which are marked $numberLong so they do not silently become doubles).

Status

1.0.0 — early, and 0.x means breaking changes are expected.

631 tests across 17 files. Implemented and covered: the local database, Mongoose-shaped schema and validation, decorators, indexes with real E11000 enforcement, the lazy query builder, populate, documents with .save(), aggregation, UTC timestamps and timezones, MongoDB Extended JSON and CSV interop, the offline mutation queue, the sync engine with all five conflict strategies, and the inspector protocol.

New in 0.2.0

  • updateMany and deleteMany on the inspector protocol, behind a new documents:bulk capability. Both route through the ordinary Model API, so a bulk write from Anchor Lens validates, stamps and queues exactly like an app write. An empty filter is refused unless explicitly acknowledged — an inspector that can empty a collection on a mis-tap is worse than one that asks twice. The capability is negotiated, so an older agent and a newer Lens still connect.
  • CSV export and import, and a filter on export.
  • A MongoDB bridge protocol (MongoBridgeClient), so Anchor Lens can pull collections from a real MongoDB or push a device into one. The driver runs in anchordb-relay — React Native has no TCP sockets — and both directions carry the same Extended JSON as the file export.
  • default Extended JSON mode.
  • A no-op update is now matched but not modified, as in MongoDB: modifiedCount excludes documents the update did not change, and their updatedAt and version key are left alone. It previously counted every match, because the timestamp was stamped before the comparison. Beyond correctness this matters for bulk writes — setting a field over 10,000 documents no longer queues 10,000 mutations when only a few hundred needed changing.

What is NOT verified

Stated plainly rather than left to be discovered:

  • Expo SQLite and Capacitor SQLite have never been executed. They are written against the documented APIs and typechecked, but this package is developed on a machine with no simulator or device. All of their query, index and unique-enforcement logic is inherited from a shared base that is covered by the conformance suite; the unverified surface is roughly forty lines of driver plumbing each. Test on a device before relying on them in production.
  • The REST sync transport is typechecked but has no live-HTTP test. The protocol it speaks is covered end to end through an in-process transport.
  • MongooseStore in anchordb-sync-server has not run against a live MongoDB here.

Not supported in v1

Documented rather than silently absent: discriminators, refPath, transactions/sessions, server-side change streams, text/2dsphere/hashed indexes, collation, and the $graphLookup/$geoNear/$search/$merge/$out/$unionWith aggregation stages.

The AnchorDB family

Six packages. Only anchordb is required — the rest exist so that an offline-only app never has to download Express, and an Express server never has to download React.

| Package | What it is | Runs where | | --- | --- | --- | | anchordb (this package) | The database — schema, models, queries, aggregation, optional sync | phone · browser · Node | | anchordb-react | React and React Native hooks | the device | | anchordb-angular | Angular / Ionic module, DI and RxJS observables | the device | | anchordb-sync-server | Server half of sync — Express, NestJS, Next.js | your backend | | anchordb-relay | Dev relay for the Anchor Lens inspector | your laptop | | anchordb-lens-link | Open a QA build's database in Anchor Lens on the same phone, from a file | the device, in QA builds |

Each one needs a different third-party framework as a peer dependency, and npm resolves those per package rather than per import — which is why they are not one package. Full reasoning and API reference: github.com/knnadeera/anchordb.

Bugs, support and feedback

Report a bug, ask for help or suggest a feature on the AnchorDB project page — choose anchordb as the package, and the reply comes by email.

A report that can be acted on straight away has:

  • the package and exact version — what npm ls anchordb prints
  • where it runs — Expo, Ionic, a browser or Node — and which storage adapter
  • the smallest snippet that reproduces it
  • the full error, including code, keyPattern and keyValue for an E11000
  • what you expected to happen instead

Sync problems: say which conflict strategy you use, and whether the mutation shows as parked in Anchor Lens — a push rejected by a unique index is parked rather than retried forever.

License

MIT