# Changes in each package

Every package below is released at the same version as `keyv` from v6 on. All of them extend Hookified, declare the v6 storage contract, and take an absolute `expires` timestamp when you call them directly (see [Calling an adapter directly](#calling-an-adapter-directly)). Keys that the old versions wrote are covered in [stored-data.md](stored-data.md).

## `@keyv/redis`

- Built on the official `redis` client (`@redis/client` v6). The v4-era 2.x line used `ioredis`; see [v4-to-v5.md](v4-to-v5.md#keyvredis-moved-to-the-official-redis-client).
- `new KeyvRedis(connect, options)` takes a connection string, `redis` client options, or a client from the exported `createClient`, `createCluster`, or `createSentinel`. `createClient` takes an options object, as in `createClient({ url: 'redis://localhost:6379' })`, not a string.
- Options: `namespace`, `namespaceSeparator` (default `::`; v5 called it `keyPrefixSeparator`, and v6 ignores that name in plain JavaScript), `clearBatchSize`, `useUnlink`, `noNamespaceAffectsAll`, `throwOnConnectError`, `throwOnErrors`, `connectionTimeout`. `throwOnErrors` here is the adapter's own option: keep it. Only the Keyv option of that name was removed.
  - `throwOnConnectError` (default `true`): a failed connection rejects the operation that tried to connect.
  - `throwOnErrors` (default `false`): a failed command emits `error` and returns `undefined` or `false`; with `true` it rejects instead.
  - Either way, Keyv then applies its own error rule; see [v5-to-v6.md](v5-to-v6.md#errors).
- The client connects on the first command, not when the adapter is created.
- The namespace defaults to `undefined`. With a namespace, `clear()` and `iterator()` cover the string keys that start with `<namespace><namespaceSeparator>`, matched literally. In v5 a `*`, `?`, `[`, `]` or `\` in either was read as `SCAN` pattern syntax, so `clear()` on namespace `tenant*` also deleted namespace `tenant-prod`. Code that relied on that must clear each namespace itself. With no namespace, `clear()` deletes every string key without the separator in its name.
- A failure is reported once: when the adapter rejects, it no longer also emits `error`.
- CommonJS: `const KeyvRedis = require('@keyv/redis').default`. There is no named `KeyvRedis` export.
- `createKeyv(connect, options)` and `createKeyvNonBlocking(connect, options)` return a ready `Keyv`. They no longer set any Keyv error options.

## `@keyv/valkey`

- `useRedisSets` is now `useSets`, and it defaults to `false`. The old name still works as a deprecated getter and setter.
- The `redis` property is now `client`.
- Data keys are `namespace:<ns>::<key>`, or `sets:<ns>::<key>` with `useSets: true`; `namespaceSeparator` (default `::`) sets the separator before the key. The set that tracks keys is `sets:<ns>` (v5: `namespace:<ns>`).
- Missing values are `undefined`, never `null`.
- `keyv` is now a peer dependency; install it next to the adapter.

## `@keyv/sqlite`

- The driver changed. v6 uses `node:sqlite` on Node.js and `bun:sqlite` on Bun, and falls back to `better-sqlite3`. It no longer uses `sqlite3`. To keep `sqlite3`, pass `createSqlite3Driver(sqlite3)` as the driver; otherwise remove the `sqlite3` dependency.
- The adapter opens the database when it is created, and a v4 or v5 table converts right then, before any read. It is one-way, so back up first, and keep tests away from a real database file; see [stored-data.md](stored-data.md#sqlite-keyvsqlite).
- `keySize` still works. `keyLength` is a deprecated alias of it here, the reverse of PostgreSQL and MySQL.
- A deprecated `opts` getter remains for backward compatibility.
- New: an `expires` column, `clearExpired()`, the `clearExpiredInterval` option, bulk operations, and `createKeyv()`.

## `@keyv/postgres`

- `keySize` is now `keyLength`, and `dialect` is gone. In JavaScript, an old `keySize` is passed to the `pg` pool and has no effect.
- Namespaces live in a `namespace` column. Old tables need the migration script; see [stored-data.md](stored-data.md#postgresql-and-mysql).
- Native TTL with an `expires` column.

## `@keyv/mysql`

- `keySize` is now `keyLength`.
- The primary key is now `(namespace, id)`, and the key column is `VARBINARY`. Old tables need the migration script; see [stored-data.md](stored-data.md#postgresql-and-mysql).
- `keyv` is now a peer dependency; install it next to the adapter.

## `@keyv/mongo`

- The version jumps from 3.x to 6.x with the rest of the family.
- Uses MongoDB driver v7.
- Namespaces live in a `namespace` field (`metadata.namespace` with GridFS), and the unique index is `{ key: 1, namespace: 1 }`. Old documents need the migration script; see [stored-data.md](stored-data.md#mongodb-keyvmongo).
- `useGridFS` can only be set in the constructor. `ttlSupport` was removed. Options are strictly typed, so unknown options are TypeScript errors.
- New: `createKeyv`, `setMany`, `hasMany`, `clearExpired`, `clearUnusedFor`.

## `@keyv/memcache`

- Uses the `memcache` client instead of `memjs`. `store.client` is a `Memcache` instance, and options extend `MemcacheOptions`. Update any `memjs`-specific options.
- Credentials move out of the server string: `new KeyvMemcache('localhost:11211', { sasl: { username, password } })`.
- Values are handled as strings, not Buffers. `disconnect()` was added.
- `clear()` removes only the store's own entries: each namespace has a generation token, and `clear()` writes a new one. v4 and v5 flushed the whole server. With no namespace, `noNamespaceAffectsAll: true` flushes it, as before.
- Values v4 and v5 wrote have no generation token, so v6 reads them as missing.
- Keys are `<ns>::<key>`. The new `namespaceSeparator` option (default `::`) sets the separator.

## `@keyv/etcd`

- Keys are `<ns>::<key>`. v4 and v5 used `ns:foo`, so reading their keys needs `namespaceSeparator: ':'`; see [stored-data.md](stored-data.md#etcd-and-dynamodb).
- The `etcd3` dependency is gone. The adapter talks to etcd's HTTP/JSON gateway, so it needs etcd 3.4 or later with the gateway on (the default).
- The `lease` property was removed. The store `ttl` option now applies to each key from its own write. In v5 it created one lease at startup that expired every key at once, after which writes failed.
- `ttlSupport` and `opts` were removed. `store.client` is the adapter's own `EtcdClient`.
- With no namespace, `clear()` and `iterator()` touch only the entries v6 wrote without a namespace. In v5 they covered every key in etcd. Entries v5 wrote are left alone. `noNamespaceAffectsAll: true` brings back the v5 behavior.

## `@keyv/dynamo`

- Keys are `<ns>::<key>`. v5 used `ns:foo`, so reading its keys needs `namespaceSeparator: ':'`; see [stored-data.md](stored-data.md#etcd-and-dynamodb).
- Keys written without a TTL no longer get a six-hour expiry. To keep one, set Keyv's `ttl` option: `new Keyv(store, { ttl: 6 * 60 * 60 * 1000 })`.
- `sixHoursInMilliseconds` was removed. Keys written by v5 keep the expiry they were written with.
- `ttlSupport` and `opts` were removed.

## `@keyv/bigmap`

- Emits Hookified events (`BigMapEvents`). The `MapInterfacee` type is now `MapInterface`.
- `set()` returns the BigMap, like `Map`.
- The default `storeSize` changed, and a custom hash function now receives the real `storeSize`. Check any code that depends on how keys are distributed.
- Setting `storeSize` or `storeHashFunction` keeps every entry. In v5, setting `storeSize` removed them all, and setting `storeHashFunction` left them where `get()` couldn't find them. If code set `storeSize` to empty the map, add a `clear()` call.
- No default export: `import { BigMap, createKeyv } from '@keyv/bigmap'`.

## Compression: `@keyv/compress-gzip`, `@keyv/compress-brotli`, `@keyv/compress-lz4`

- Each adapter implements `compress(value: string): Promise<string>` and `decompress(value: string): Promise<string>` and returns base64. The v5 `serialize`, `deserialize`, and `opts` members, and per-call options, are gone.
- Gzip uses pako v3; constructor options are pako options.
- Brotli dropped the `compress-brotli` package for `node:zlib`. Options are `{ compressOptions, decompressOptions }`; `enable`, `serialize`, `deserialize`, and `iltorb` are gone.
- LZ4 still takes an optional dictionary string.
- v6 can't read entries that v4 or v5 compressed; see [stored-data.md](stored-data.md#compressed-data).

## New packages

- Serializers: `@keyv/serialize-superjson` (`superJsonSerializer`) and `@keyv/serialize-msgpackr` (`msgpackrSerializer`). Pass one as `serialization`.
- Encryption: `@keyv/encrypt-node` (`KeyvEncryptNode`) and `@keyv/encrypt-web` (`KeyvEncryptWeb`). Pass one as `encryption`.
- Storage: `@keyv/cloudflare-kv` (`KeyvCloudflareKV`).

## Calling an adapter directly

Code that calls an adapter's methods without going through Keyv must pass an absolute Unix timestamp in milliseconds as `expires`, not a relative `ttl`. Passing `5000` means five seconds after 1970, so the entry is already expired.

```js
// v5
await store.set('foo', 'bar', 5000);
await store.setMany([{ key: 'a', value: '1', ttl: 5000 }]);

// v6
await store.set('foo', 'bar', Date.now() + 5000);
await store.setMany([{ key: 'a', value: '1', expires: Date.now() + 5000 }]);
```

Keyv's own `set(key, value, ttl)` still takes a relative TTL.
