Keyv v5 is a major release with breaking changes. The biggest one is that Keyv no longer loads storage adapters from a connection string. This page covers what changed from v4 to v5.
Still on v4? Go straight to v6. Apply this page, then the v5 to v6 guide. See Going Straight from v4 to v6 for the parts that differ for v4 data.
Using an AI coding agent? Tell it: "Upgrade this project to Keyv v6 using https://keyv.org/skills/migrate". The skill handles v4 projects too. See Migrate with an AI Agent.
Table of Contents
- New Features
Pass a Storage Adapter Instead of a Connection String
Before with v4
import Keyv from 'keyv';
import KeyvRedis from '@keyv/redis';
const keyv = new Keyv('redis://user:pass@localhost:6379');
v4 read the scheme from the string, or from the adapter option, and loaded the matching @keyv/* package for you. Now you pass the store either directly to the constructor, as below, or in the store option. The constructor takes the storage adapter or the options as the first parameter.
Watch out: v5 and v6 don't reject a connection string. new Keyv('redis://...') and new Keyv({ uri: 'redis://...' }) silently fall back to an in-memory store, and TypeScript accepts both forms. Search your code for every place that builds a Keyv from a string.
Now with v5
import Keyv from 'keyv';
import KeyvRedis from '@keyv/redis';
const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379'));
An example with options
When passing in options you can do the following using the store parameter:
import Keyv from 'keyv';
import KeyvRedis from '@keyv/redis';
const keyv = new Keyv(new KeyvRedis('redis://user:pass@localhost:6379',{ namespace: 'my-namespace' }));
v4 also passed any extra Keyv options through to the adapter, as in new Keyv({ uri: 'sqlite://cache.sqlite', table: 'cache' }). Give adapter options to the adapter instead:
import Keyv from 'keyv';
import KeyvSqlite from '@keyv/sqlite';
const keyv = new Keyv(new KeyvSqlite({ uri: 'sqlite://cache.sqlite', table: 'cache' }));
CommonJS Imports Changed
v4 exported the class as the module itself (module.exports = Keyv). From v5 on, keyv exports Keyv as a named export and as default, so the v4 form fails with Keyv is not a constructor:
// v4
const Keyv = require('keyv');
// v5 and later
const { Keyv } = require('keyv');
// or
const Keyv = require('keyv').default;
Adapters changed the same way. In v6 most adapters also export their class by name, such as const { KeyvSqlite } = require('@keyv/sqlite'). @keyv/redis has only a default export, so use const KeyvRedis = require('@keyv/redis').default.
@keyv/offline and @keyv/tiered Were Removed
@keyv/offline and @keyv/tiered are gone, along with the offline: and tiered: connection strings. For a fast in-memory layer in front of a remote store, or for offline fallbacks, use Cacheable.
@keyv/redis Uses the Official Redis Client
The v4-era @keyv/redis 2.x was built on ioredis. Since Keyv v5, @keyv/redis uses the official redis client (@redis/client). You can't pass an ioredis instance or ioredis-only options anymore. Pass a connection string or redis client options, or create a client with the createClient, createCluster, or createSentinel functions that @keyv/redis exports. See @keyv/redis.
Other Changes
- TypeScript and ESM. v5 is written in TypeScript and ships ESM and CommonJS builds with its own types. v4's
Keyv<Value, Options>type took an options parameter; v5 and v6 take only the value type, as inKeyv<Value>. - Return values. v4's
setalways resolvedtrue. Now a failed write is reported; v6 returnsfalseor rejects depending on whether anerrorlistener is attached.hasalso accepts an array of keys, andhasManywas added. v4'sdelete([...])with an array resolved one boolean: with aMap, Memcache, or Etcd it wastrueonly when every key was deleted, and with SQLite, PostgreSQL, MySQL, or MongoDB when any key was. With Redis it depended on the@keyv/redisversion: 2.7 through 3.0 meant every key, and earlier and later versions any key. v6 returns one boolean per key. - Raw values. v4 stored
expires: nullfor entries without a TTL. v5 and v6 leaveexpiresout, so checkexpires === undefinedrather than=== null. - Serialization. v4 serialized with
json-buffer. v5 used@keyv/serialize, and v6 has a built-in serializer. All three write the same format, so data v4 wrote without compression can still be read. - Compression. In v4, a compression adapter replaced
serializeanddeserializeentirely. v6 can't read values that v4 compressed. - Events. v4 extended Node.js's
EventEmitter. v5 has its own event emitter, and v6 uses Hookified. In v4,emitErrorscould only be set in the constructor; v6 removed it. - Errors. In v4, a call rejected whenever the store failed, even with an
errorlistener attached; the listener only received errors the store emitted on its own, such as a dropped connection. In v6, attaching a listener makes failed calls return fallback values instead of rejecting. A v4 app that addedkeyv.on('error', ...)for connection errors, and still relies on calls rejecting, changes behavior silently. See Error Handling Changed. - Iterator. v4 attached
iteratoronly for aMapand some adapters, and you passed it the namespace:keyv.iterator(keyv.opts.namespace). In v6,keyv.iterator()always exists and takes no arguments.
Removing support for Nodejs 18 and below
We have stopped testing on Nodejs 18 and below and while we do not force or require you to use Nodejs 20+ we do recommend it. Keyv v6 requires Node.js 22.19 or later.
Going Straight from v4 to v6
Apply this page first, then the v5 to v6 guide. Most of that guide applies to v4 projects as written, including the table for keeping existing data readable. v4 stored keys the same way v5 did for SQLite, PostgreSQL, MySQL, MongoDB, Etcd, and Memcache, so use the "default" rows of that table.
Redis is different. @keyv/redis 2.x, the version used with Keyv v4, stored Keyv's key without adding a prefix of its own. In this table, ns is the namespace your v4 instance used, which is keyv unless you set one:
| v4 setup | Key v4 stored for foo |
v6 setting that reads it |
|---|---|---|
| default | ns:foo |
namespace: 'ns' with new KeyvRedis(uri, { keyPrefixSeparator: ':' }) |
useRedisSets: false |
sets:namespace:ns:ns:foo |
namespace: 'sets:namespace:ns:ns' with new KeyvRedis(uri, { keyPrefixSeparator: ':' }) |
v4's Redis adapter also kept a Redis set named namespace:ns that listed its keys. v6 doesn't use it, so you can delete it once nothing runs v4.
Values that v4 wrote with compression can't be read by v6. Treat them as a cache to repopulate.
New Features
Here are a list of new features in Keyv v5:
- Typescript Support: Keyv v5 is written in Typescript and has full typescript support.
- ESM Support: Keyv v5 is written in ESM and has full ESM support.
- Event Emitter: Keyv v5 is now an event emitter and emits events for
set,delete,clear, anderrorwith no reliance on third party libraries. - Built in Statistics: Keyv v5 has built in statistics for
hits,misses,sets,deletes, anderrors. - Hooks: Keyv v5 has hooks for pre and post processing on
set(),get(),getMany(), anddelete().
You can learn about any of these features in the Keyv API documentation.