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

@keyv/mongo

v6.1.0

Published

MongoDB storage adapter for Keyv

Readme

@keyv/mongo

MongoDB storage adapter for Keyv

build codecov npm npm

MongoDB storage adapter for Keyv.

Uses TTL indexes to automatically remove expired documents. However MongoDB doesn't guarantee data will be deleted immediately upon expiration, so expiry dates are revalidated in Keyv.

Table of Contents

Install

npm install --save keyv @keyv/mongo

Usage

import Keyv from 'keyv';
import KeyvMongo from '@keyv/mongo';

const keyv = new Keyv(new KeyvMongo('mongodb://user:pass@localhost:27017/dbname'));
keyv.on('error', handleConnectionError);

You can specify the collection name, by default 'keyv' is used.

e.g:

const keyv = new Keyv(new KeyvMongo('mongodb://user:pass@localhost:27017/dbname', { collection: 'cache' }));

You can also use the createKeyv helper function to create a Keyv instance with KeyvMongo as the store:

import { createKeyv } from '@keyv/mongo';

const keyv = createKeyv('mongodb://user:pass@localhost:27017/dbname');

Constructor Options

The KeyvMongo constructor accepts a connection URI string or an options object:

// With URI string
const store = new KeyvMongo('mongodb://user:pass@localhost:27017/dbname');

// With options object
const store = new KeyvMongo({
  url: 'mongodb://user:pass@localhost:27017/dbname',
  collection: 'cache',
  db: 'mydb',
  useGridFS: false,
});

// With URI string and additional options
const store = new KeyvMongo('mongodb://user:pass@localhost:27017/dbname', { collection: 'cache' });

| Option | Type | Default | Description | |---|---|---|---| | url | string | 'mongodb://127.0.0.1:27017' | MongoDB connection URI | | collection | string | 'keyv' | Collection name for storage | | namespace | string \| undefined | undefined | Namespace for keys, stored in each document's namespace field | | useGridFS | boolean | false | Whether to use GridFS for storing values | | db | string \| undefined | undefined | Database name | | readPreference | ReadPreference \| undefined | undefined | MongoDB read preference for GridFS operations |

Any additional options are passed through to the MongoDB driver as MongoClientOptions.

Properties

Most configuration options are exposed as properties with getters and setters on the KeyvMongo instance. You can read or update them after construction. Some properties like useGridFS are read-only and can only be set via the constructor.

url

Get or set the MongoDB connection URI.

  • Type: string
  • Default: 'mongodb://127.0.0.1:27017'
const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname' });
console.log(store.url); // 'mongodb://user:pass@localhost:27017/dbname'

collection

Get or set the collection name used for storage.

  • Type: string
  • Default: 'keyv'
const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname' });
console.log(store.collection); // 'keyv'
store.collection = 'cache';

namespace

Get or set the namespace for the adapter. It is stored in each document's namespace field (or metadata.namespace with GridFS) and scopes operations like clear().

  • Type: string | undefined
  • Default: undefined
const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname' });
store.namespace = 'my-namespace';
console.log(store.namespace); // 'my-namespace'

useGridFS

Get whether GridFS is used for storing values. When enabled, values are stored using MongoDB's GridFS specification, which is useful for storing large files. This property is read-only and can only be set via the constructor, because the connection shape differs between GridFS and standard modes.

Each value is a GridFS file named after its key. set writes a new file and then deletes the key's older files, so a key keeps a single file. Reads always use the newest file for a key, and delete removes every file for it.

  • Type: boolean
  • Default: false
  • Read-only (set via constructor only)
const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017/dbname', useGridFS: true });
console.log(store.useGridFS); // true

db

Get or set the database name for the MongoDB connection.

  • Type: string | undefined
  • Default: undefined
const store = new KeyvMongo({ url: 'mongodb://user:pass@localhost:27017', db: 'mydb' });
console.log(store.db); // 'mydb'

readPreference

Get or set the MongoDB read preference for GridFS operations.

  • Type: ReadPreference | undefined
  • Default: undefined
import { ReadPreference } from 'mongodb';

const store = new KeyvMongo({
  url: 'mongodb://user:pass@localhost:27017/dbname',
  useGridFS: true,
  readPreference: ReadPreference.SECONDARY,
});
console.log(store.readPreference); // ReadPreference.SECONDARY

Methods

set

set(key, value, expires?) - Set a value in the store.

  • key (string) - The key to set.
  • value (any) - The value to store.
  • expires (number, optional) - Absolute expiry time as a Unix timestamp in milliseconds (Date.now() + ttl). If specified, the key expires at this time.
  • Returns: Promise<boolean>

Through a Keyv instance, keyv.set(key, value, ttl) still takes a relative ttl in milliseconds. Keyv converts it to expires before it calls the adapter.

const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store });

await keyv.set('foo', 'bar');
await keyv.set('foo', 'bar', 5000); // Keyv takes a relative ttl: expires in 5 seconds

await store.set('foo', 'bar', Date.now() + 5000); // the adapter takes an absolute expires

setMany

setMany(entries) - Set multiple values in the store at once.

  • entries (KeyvStorageEntry[]) - Array of entries to set. Each entry has a key, value, and optional expires (an absolute Unix timestamp in milliseconds). A ttl field is ignored. Value is inferred from the entries provided.
  • Returns: Promise<boolean[]> - An array of booleans indicating whether each entry was set successfully.

Through a Keyv instance, keyv.setMany() takes entries with a relative ttl ({ key, value, ttl? }) and converts them before it calls the adapter.

In standard mode, uses a single unordered MongoDB bulkWrite operation for efficiency with per-entry error tracking — if individual writes fail, only those entries return false. In GridFS mode, each entry is set individually in parallel using Promise.allSettled, providing per-entry success tracking.

const store = new KeyvMongo('mongodb://localhost:27017');

const results = await store.setMany([
  { key: 'key1', value: 'value1' },
  { key: 'key2', value: 'value2', expires: Date.now() + 5000 },
]); // [true, true]

get

get(key) - Get a value from the store.

  • key (string) - The key to retrieve.
  • Returns: Promise<any> - The stored value, or undefined if the key does not exist.

In GridFS mode, get also updates the lastAccessed timestamp on the file, which is used by clearUnusedFor.

const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store });

await keyv.set('foo', 'bar');
const value = await keyv.get('foo');
console.log(value); // 'bar'

const missing = await keyv.get('nonexistent');
console.log(missing); // undefined

getMany

getMany(keys) - Get multiple values from the store at once.

  • keys (string[]) - Array of keys to retrieve.
  • Returns: Promise<Array<any>> - Array of values in the same order as the input keys. Missing keys return undefined at their position.

In standard mode, uses a single MongoDB query with the $in operator for efficiency. In GridFS mode, each key is fetched individually.

const store = new KeyvMongo('mongodb://localhost:27017');

await store.set('key1', 'value1');
await store.set('key2', 'value2');

const values = await store.getMany(['key1', 'key2', 'key3']);
console.log(values); // ['value1', 'value2', undefined]

has

has(key) - Check if a key exists in the store.

  • key (string) - The key to check.
  • Returns: Promise<boolean> - true if the key exists, false otherwise.
const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store });

await keyv.set('foo', 'bar');
console.log(await keyv.has('foo')); // true
console.log(await keyv.has('nonexistent')); // false

hasMany

hasMany(keys) - Check if multiple keys exist in the store at once.

  • keys (string[]) - Array of keys to check.
  • Returns: Promise<boolean[]> - Array of booleans in the same order as the input keys.

Uses a single MongoDB query with the $in operator for efficiency in both standard and GridFS modes.

const store = new KeyvMongo('mongodb://localhost:27017');

await store.set('key1', 'value1');
await store.set('key2', 'value2');

const results = await store.hasMany(['key1', 'key2', 'key3']);
console.log(results); // [true, true, false]

delete

delete(key) - Delete a key from the store.

  • key (string) - The key to delete.
  • Returns: Promise<boolean> - true if the key was deleted, false if the key was not found.
const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store });

await keyv.set('foo', 'bar');
console.log(await keyv.delete('foo')); // true
console.log(await keyv.delete('nonexistent')); // false

deleteMany

deleteMany(keys) - Delete multiple keys from the store at once.

  • keys (string[]) - Array of keys to delete.
  • Returns: Promise<boolean[]> - An array of booleans indicating whether each key was deleted.

Each key is deleted individually in parallel so that per-key success/failure information is preserved in the returned array.

const store = new KeyvMongo('mongodb://localhost:27017');

await store.set('key1', 'value1');
await store.set('key2', 'value2');

const results = await store.deleteMany(['key1', 'key2', 'key3']); // [true, true, false]

clear

clear() - Delete all keys in the current namespace.

  • Returns: Promise<void>

Only keys matching the current namespace are removed. If no namespace is set, all keys with an empty namespace are cleared.

const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store, namespace: 'my-namespace' });

await keyv.set('key1', 'value1');
await keyv.set('key2', 'value2');

await keyv.clear(); // removes all keys in 'my-namespace'

iterator

iterator() - Iterate over all key-value pairs in the store. The iterator uses the namespace configured on the instance.

  • Returns: AsyncGenerator<[string, any]> - An async generator yielding [key, value] pairs.
const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store, namespace: 'ns' });

await keyv.set('key1', 'value1');
await keyv.set('key2', 'value2');

for await (const [key, value] of keyv.iterator()) {
  console.log(key, value); // 'key1' 'value1', 'key2' 'value2'
}

disconnect

disconnect() - Close the MongoDB connection.

  • Returns: Promise<void>
const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store });

// ... use the store ...

await keyv.disconnect();

clearExpired

clearExpired() - Remove all expired files from GridFS. This method only works in GridFS mode and is a no-op that returns false in standard mode.

  • Returns: Promise<boolean> - true if running in GridFS mode, false otherwise.

This is useful for manual cleanup of expired GridFS files, since GridFS does not support MongoDB TTL indexes.

const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });

await store.set('temp', 'data', Date.now() + 1000); // adapter takes an absolute expires (Unix ms); expires in ~1 second

// After expiration...
await store.clearExpired(); // removes expired GridFS files

clearUnusedFor

clearUnusedFor(seconds) - Remove all GridFS files that have not been accessed for the specified duration. This method only works in GridFS mode and is a no-op that returns false in standard mode.

  • seconds (number) - The number of seconds of inactivity after which files should be removed.
  • Returns: Promise<boolean> - true if running in GridFS mode, false otherwise.

The lastAccessed timestamp is updated each time a file is read via get.

const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });

await store.set('foo', 'bar');

// Remove files not accessed in the last hour
await store.clearUnusedFor(3600);

Migration from v3 to v6

@keyv/mongo is jumping from v3 to v6 because the entire Keyv monorepo is now unified under a single version number. This approach, similar to what other popular open source projects do, keeps all @keyv/* packages in sync and makes it easier to reason about compatibility across the ecosystem.

Breaking Changes

MongoDB Driver Upgraded to v7

The mongodb dependency has been upgraded from ^6.x to ^7.0.0. Review the MongoDB Node.js Driver v7 release notes for any breaking changes that may affect your application.

Event Handling: EventEmitter Replaced with Hookified

KeyvMongo no longer extends Node.js EventEmitter. It now extends Hookified, which provides hook-based event management.

// v3 - EventEmitter
const store = new KeyvMongo('mongodb://localhost:27017');
store.on('error', err => console.error(err));

// v6 - Hookified (same usage for basic events)
const store = new KeyvMongo('mongodb://localhost:27017');
store.on('error', err => console.error(err));

For most use cases the .on() API is the same, but if you relied on EventEmitter-specific methods like .listenerCount(), .rawListeners(), or .prependListener(), check the Hookified documentation for equivalents.

useGridFS is Now Read-Only

The useGridFS property can no longer be changed after construction. The connection shape differs between GridFS and standard modes, so this must be set at construction time.

// v3 - Could change after instantiation
const store = new KeyvMongo('mongodb://localhost:27017');
store.useGridFS = true; // worked in v3

// v6 - Must set at construction
const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
console.log(store.useGridFS); // true (read-only)

ttlSupport Property Removed

The ttlSupport property has been removed. If your code checks for TTL support on the adapter, remove those checks.

set Takes an Absolute expires

The third argument of the adapter's set is now an absolute Unix timestamp in milliseconds, not a relative ttl. This only affects code that calls the adapter directly. keyv.set(key, value, ttl) still takes a relative ttl.

// v3 - relative ttl
await store.set('foo', 'bar', 5000);

// v6 - absolute expires
await store.set('foo', 'bar', Date.now() + 5000);

Namespaces Are Stored in Their Own Field

v3 stored the namespace as a prefix of each key (key: "keyv:foo") and wrote no namespace field. v6 stores it separately (key: "foo", namespace: "keyv") and only reads documents that have a namespace field, so documents written by v3 stay invisible to v6 until you run the migration script.

The unique index on the underlying MongoDB collection has also changed from { key: 1 } to { key: 1, namespace: 1 }, so the same key can exist in different namespaces. The adapter drops the old index and creates the new one when it connects.

Options Type is Now Strongly Typed

The constructor options no longer accept arbitrary keys via [key: string]: unknown. Options are now strictly typed with explicit properties. Any additional MongoDB driver options should be valid MongoClientOptions properties.

// v3 - Accepted any properties
const store = new KeyvMongo({ url: 'mongodb://...', customProp: true }); // no type error

// v6 - Strictly typed
const store = new KeyvMongo({ url: 'mongodb://...', collection: 'cache' }); // only known props + MongoClientOptions

New Features

createKeyv Helper Function

A new createKeyv helper simplifies creating a Keyv instance with the MongoDB adapter.

import { createKeyv } from '@keyv/mongo';

// Before
const store = new KeyvMongo('mongodb://localhost:27017');
const keyv = new Keyv({ store, namespace: 'my-ns' });

// After
const keyv = createKeyv({ url: 'mongodb://localhost:27017', namespace: 'my-ns' });

setMany Method

Batch set multiple key-value pairs in a single operation using MongoDB bulkWrite. Each entry takes an optional absolute expires timestamp (Unix ms).

await store.setMany([
  { key: 'key1', value: 'value1' },
  { key: 'key2', value: 'value2', expires: Date.now() + 5000 },
]);

hasMany Method

Check if multiple keys exist in a single query using the $in operator.

const results = await store.hasMany(['key1', 'key2', 'key3']);
// [true, true, false]

clearExpired Method

Manually remove expired files from GridFS storage.

const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
await store.clearExpired();

clearUnusedFor Method

Remove GridFS files that have not been accessed for a specified duration.

const store = new KeyvMongo({ url: 'mongodb://localhost:27017', useGridFS: true });
await store.clearUnusedFor(3600); // remove files unused for 1 hour

Running the migration script

If you have documents written by @keyv/mongo v3, run the migration script so v6 can read them. The script ships in the npm package at scripts/migrate-v6.ts. Run it from your project root with tsx. Node.js refuses to strip TypeScript types from files under node_modules, so running the script with plain node from there fails with ERR_UNSUPPORTED_NODE_MODULES_TYPE_STRIPPING.

Preview the changes first with --dry-run. Dry-run mode only counts and previews the documents that would change:

npx tsx node_modules/@keyv/mongo/scripts/migrate-v6.ts --uri mongodb://user:pass@localhost:27017/dbname --dry-run

Run the migration:

npx tsx node_modules/@keyv/mongo/scripts/migrate-v6.ts --uri mongodb://user:pass@localhost:27017/dbname

Pass --collection if you set a custom collection, --db if the database is not in the URI, and --gridfs for a store created with useGridFS: true:

npx tsx node_modules/@keyv/mongo/scripts/migrate-v6.ts --uri mongodb://user:pass@localhost:27017 --db cache --collection sessions
npx tsx node_modules/@keyv/mongo/scripts/migrate-v6.ts --uri mongodb://user:pass@localhost:27017/dbname --gridfs

From a clone of this repo you can run node scripts/migrate-v6.ts in storage/mongo with the same flags.

Important notes:

  • The script only changes documents that have no namespace field, so it is safe to run again. Documents already in the v6 layout are never touched.
  • Keys are split on the first colon: the part before becomes the namespace, the rest becomes the key. A key without a colon gets the empty namespace v6 uses when none is set. Namespaces containing colons are not supported. The split is also wrong for colon-containing keys that Keyv v5 stored without a prefix, which happens only when it ran with useKeyPrefix: false or an empty namespace.
  • Keyv v5 used keyv as the namespace when none was set, so those documents migrate into namespace keyv. Pass namespace: 'keyv' to Keyv afterwards to keep reading them. See the v5 to v6 migration guide.
  • In standard mode the script first replaces the unique index on key with the unique index on { key, namespace }, the same change the adapter makes when it connects.
  • If v6 already stores a value under the same key and namespace, that value was written after the upgrade and is kept. The v3 document is left unchanged and listed in the output.
  • In GridFS mode, v3 kept every revision of a file and read the newest. The script migrates only the newest revision of each key and lists the older ones, which v6 cannot read.
  • The rewrite is not transactional. If it stops part way, documents already migrated keep their new layout, so run the script again to finish.

License

MIT © Jared Wray