@keyv/etcd

Etcd storage adapter for Keyv using the etcd3 client

build codecov GitHub license npm npm

Features

  • Built on the etcd3 package with full TypeScript support
  • TTL support via etcd leases (millisecond input, converted to seconds internally)
  • Namespace support for key isolation across multiple Keyv instances
  • Async iterator support for scanning keys
  • setMany, getMany, deleteMany, and hasMany batch operations
  • createKeyv helper for quick setup

Table of Contents

Install

npm install --save keyv @keyv/etcd
    

Quick Start with createKeyv

import { createKeyv } from '@keyv/etcd';
    
    const keyv = createKeyv('etcd://localhost:2379');
    
    // set a value
    await keyv.set('foo', 'bar');
    
    // get a value
    const value = await keyv.get('foo');
    
    // set with TTL (milliseconds)
    await keyv.set('foo', 'bar', 6000);
    
    // delete a value
    await keyv.delete('foo');
    

You can also pass options:

import { createKeyv } from '@keyv/etcd';
    
    const keyv = createKeyv('etcd://localhost:2379', { ttl: 5000 });
    
    // or using an options object
    const keyv2 = createKeyv({ url: '127.0.0.1:2379', ttl: 5000 });
    

Usage

import Keyv from 'keyv';
    import KeyvEtcd from '@keyv/etcd';
    
    const store = new KeyvEtcd('etcd://localhost:2379');
    const keyv = new Keyv({ store });
    
    // set a value
    await keyv.set('foo', 'bar');
    
    // set a value with TTL (in milliseconds)
    await keyv.set('foo', 'bar', 6000);
    
    // get a value
    const value = await keyv.get('foo');
    
    // delete a value
    await keyv.delete('foo');
    
    // clear all values
    await keyv.clear();
    
    // disconnect
    await store.disconnect();
    

Usage with Namespaces

import Keyv from 'keyv';
    import KeyvEtcd from '@keyv/etcd';
    
    const store = new KeyvEtcd('etcd://localhost:2379');
    const keyv1 = new Keyv({ store, namespace: 'namespace1' });
    const keyv2 = new Keyv({ store, namespace: 'namespace2' });
    
    // keys are isolated by namespace
    await keyv1.set('foo', 'bar1');
    await keyv2.set('foo', 'bar2');
    
    const value1 = await keyv1.get('foo'); // 'bar1'
    const value2 = await keyv2.get('foo'); // 'bar2'
    

Options

Option Type Default Description
url string '127.0.0.1:2379' The etcd server URL. The etcd:// protocol prefix is automatically stripped.
uri string Alias for url
ttl number undefined Default TTL in milliseconds for all keys. Uses etcd leases internally.
busyTimeout number undefined Busy timeout in milliseconds
dialect string 'etcd' Storage dialect identifier (read-only)
namespace string undefined Key prefix for namespace isolation
import KeyvEtcd from '@keyv/etcd';
    
    // Using a URI string
    const store = new KeyvEtcd('etcd://localhost:2379');
    
    // Using an options object
    const store2 = new KeyvEtcd({ url: '127.0.0.1:2379', ttl: 5000 });
    
    // Using a URI string with additional options
    const store3 = new KeyvEtcd('etcd://localhost:2379', { ttl: 5000, busyTimeout: 3000 });
    

Properties

.client

The underlying Etcd3 client instance. Can be used to access the etcd3 client directly.

Type Default
Etcd3 Created from the url option

.lease

The etcd lease used for TTL support. Only set when a ttl is configured.

Type Default
Lease | undefined undefined

.url

The etcd server URL.

Type Default
string '127.0.0.1:2379'

.ttl

Default TTL in milliseconds for all keys. Converted to seconds internally for etcd leases.

Type Default
number | undefined undefined

.busyTimeout

Busy timeout in milliseconds.

Type Default
number | undefined undefined

.dialect

Storage dialect identifier. Always returns 'etcd'. Read-only.

Type Default
string 'etcd'

.namespace

Key prefix for namespace isolation. When set, all keys are prefixed with namespace:.

Type Default
string | undefined undefined

.keyPrefixSeparator

The separator between the namespace and key.

Type Default
string ':'

.opts

Read-only object containing the current configuration options. Provided for legacy compatibility.

Type
KeyvEtcdOptions
const store = new KeyvEtcd('etcd://localhost:2379', { ttl: 5000 });
    console.log(store.opts);
    // { url: '127.0.0.1:2379', ttl: 5000, busyTimeout: undefined, dialect: 'etcd', namespace: undefined }
    

Methods

constructor(url?, options?)

Creates a new KeyvEtcd instance.

  • url — An etcd server URI string (e.g., 'etcd://localhost:2379') or a KeyvEtcdOptions object. Defaults to '127.0.0.1:2379' if not provided.
  • options — Optional KeyvEtcdOptions object. When both url and options are objects, they are merged together.
import KeyvEtcd from '@keyv/etcd';
    
    // Using a URI string
    const store = new KeyvEtcd('etcd://localhost:2379');
    
    // Using an options object
    const store2 = new KeyvEtcd({ url: '127.0.0.1:2379', ttl: 5000 });
    
    // Using a URI string with additional options
    const store3 = new KeyvEtcd('etcd://localhost:2379', { ttl: 5000 });
    

.get(key)

Retrieves a value from the etcd server. Returns the stored value or undefined if the key does not exist.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('foo', 'bar');
    const result = await store.get('foo'); // 'bar'
    

.getMany(keys)

Retrieves multiple values from the etcd server. Returns an array of stored data corresponding to each key.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('key1', 'value1');
    await store.set('key2', 'value2');
    const results = await store.getMany(['key1', 'key2']);
    

.set(key, value)

Stores a value in the etcd server. If a default TTL is configured via the ttl option, the value is stored with an etcd lease that expires automatically.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('foo', 'bar');
    

.setMany(entries)

Stores multiple values in the etcd server. Each entry is an object with key and value properties.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.setMany([
      { key: 'key1', value: 'value1' },
      { key: 'key2', value: 'value2' },
    ]);
    

.delete(key)

Deletes a key from the etcd server. Returns true if the key was deleted, false otherwise.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('foo', 'bar');
    const deleted = await store.delete('foo'); // true
    

.deleteMany(keys)

Deletes multiple keys from the etcd server. Returns true only if all keys were successfully deleted.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('key1', 'value1');
    await store.set('key2', 'value2');
    const allDeleted = await store.deleteMany(['key1', 'key2']); // true
    

.clear()

Clears data from the etcd server. If a namespace is set, only keys with the namespace prefix are deleted. Otherwise, all keys are deleted.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.clear();
    

.has(key)

Checks whether a key exists in the etcd server.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('foo', 'bar');
    const exists = await store.has('foo'); // true
    const missing = await store.has('baz'); // false
    

.hasMany(keys)

Checks whether multiple keys exist in the etcd server. Returns an array of booleans corresponding to each key.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('key1', 'value1');
    await store.set('key2', 'value2');
    const results = await store.hasMany(['key1', 'key2', 'key3']); // [true, true, false]
    

.iterator(namespace?)

Returns an async iterator over key-value pairs. If a namespace is provided, only keys matching the namespace prefix are yielded.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.set('key1', 'value1');
    await store.set('key2', 'value2');
    
    for await (const [key, value] of store.iterator()) {
      console.log(key, value);
    }
    

.disconnect()

Gracefully disconnects from the etcd server.

const store = new KeyvEtcd('etcd://localhost:2379');
    await store.disconnect();
    

.formatKey(key)

Formats a key by prepending the namespace if one is set. If the key already starts with the namespace prefix, it is returned as-is to avoid double-prefixing.

const store = new KeyvEtcd('etcd://localhost:2379');
    store.formatKey('foo'); // 'foo'
    
    store.namespace = 'myapp';
    store.formatKey('foo'); // 'myapp:foo'
    store.formatKey('myapp:foo'); // 'myapp:foo' (no double-prefix)
    

License

MIT © Jared Wray