Nodejs Memcache Client
nodes: MemcacheNode[] (readonly)nodeIds: string[] (readonly)hash: HashProvidertimeout: numberkeepAlive: booleankeepAliveDelay: numberretries: numberretryDelay: numberretryBackoff: RetryBackoffFunctionretryOnlyIdempotent: booleanmaxKeySize: numbermaxValueSize: numbermaxExpiration: numberhashLargeKey: booleanhashery: HasherylazyConnect: boolean (readonly)get(key: string): Promisegets(keys: string[]): Promiseset(key: string, value: string, exptime?: number, flags?: number): Promiseadd(key: string, value: string, exptime?: number, flags?: number): Promisereplace(key: string, value: string, exptime?: number, flags?: number): Promisecas(key: string, value: string, casToken: string, exptime?: number, flags?: number): Promisenpm install memcache
or with pnpm:
pnpm add memcache
import { Memcache } from 'memcache';
// Create a new client
const client = new Memcache();
// Set a value
await client.set('mykey', 'Hello, Memcache!');
// Get a value
const value = await client.get('mykey');
console.log(value); // ['Hello, Memcache!']
// Delete a value
await client.delete('mykey');
// Close the connection
await client.quit();
You can also just pass in the uri into the constructor
// Single node as string
const client = new Memcache('localhost:11211');
// Single node with protocol
const client = new Memcache('memcache://192.168.1.100:11211');
// Multiple nodes with options
const client = new Memcache({
nodes: ['localhost:11211', 'server2:11211'],
timeout: 10000
});
You can specify multiple Memcache nodes by passing an array of connection strings:
import { Memcache } from 'memcache';
// Create a client with multiple nodes
const client = new Memcache({
nodes: ['localhost:11211', '192.168.1.100:11211', 'memcache://192.168.1.101:11211']
});
// Set and get values (automatically distributed across nodes)
await client.set('mykey', 'Hello, Memcache!');
const value = await client.get('mykey');
console.log(value); // ['Hello, Memcache!']
// Close the connection
await client.quit();
You can also pass an array of MemcacheNode instances for advanced configuration:
import { Memcache, createNode } from 'memcache';
// Create nodes with custom settings
const node1 = createNode('localhost', 11211, { weight: 2 });
const node2 = createNode('192.168.1.100', 11211, { weight: 1 });
const node3 = createNode('192.168.1.101', 11211, { weight: 1 });
// Create a client with MemcacheNode instances
const client = new Memcache({
nodes: [node1, node2, node3],
timeout: 10000
});
// node1 will receive twice as much traffic due to higher weight
await client.set('mykey', 'Hello, Memcache!');
const value = await client.get('mykey');
console.log(value); // ['Hello, Memcache!']
// Close the connection
await client.quit();
new Memcache(options?: string | MemcacheOptions)
Creates a new Memcache client instance. You can pass either:
Examples:
// Single node as string
const client = new Memcache('localhost:11211');
// Single node with protocol
const client = new Memcache('memcache://192.168.1.100:11211');
// Multiple nodes with options
const client = new Memcache({
nodes: ['localhost:11211', 'server2:11211'],
timeout: 10000
});
nodes?: (string | MemcacheNode)[] - Array of node URIs or MemcacheNode instances
["localhost:11211", "memcache://192.168.1.100:11212"]timeout?: number - Operation timeout in milliseconds (default: 5000)keepAlive?: boolean - Keep connection alive (default: true)keepAliveDelay?: number - Keep alive delay in milliseconds (default: 1000)hash?: HashProvider - Hash provider for consistent hashing (default: KetamaHash)retries?: number - Number of retry attempts for failed commands (default: 0)retryDelay?: number - Base delay in milliseconds between retries (default: 100)retryBackoff?: RetryBackoffFunction - Function to calculate backoff delay (default: fixed delay)retryOnlyIdempotent?: boolean - Only retry commands marked as idempotent (default: true)lazyConnect?: boolean - When true, nodes will not connect until the first command is executed. When false, nodes connect eagerly during construction (default: true)maxKeySize?: number - Maximum allowed key size in characters (default: 250, memcache protocol max)maxValueSize?: number - Maximum allowed value size in bytes (default: 1048576, memcached default)maxExpiration?: number - Maximum allowed expiration in seconds (default: 2592000, memcached's 30-day relative-time boundary). Values above this throw. 0 (no expiration) is always allowed. Raise this if you need to pass absolute Unix timestamps as expirations.hashLargeKey?: boolean | Hashery - When true, keys longer than maxKeySize are deterministically hashed via hashery (djb2 sync by default) before being sent to the server, instead of throwing. Pass a configured Hashery instance (e.g. new Hashery({ defaultAlgorithmSync: 'fnv1' })) to choose a different sync algorithm or plug in custom providers. When false, oversized keys throw a validation error (default: false). Note: hashing is one-way and can collide; two distinct long keys could map to the same hashed key.autoDiscover?: AutoDiscoverOptions - AWS ElastiCache Auto Discovery configuration (see Auto Discovery)tls?: boolean | tls.ConnectionOptions - Enable TLS for all node connections. true uses Node's default trust store (enough for publicly-trusted server certs such as AWS ElastiCache Serverless); an object is passed through to tls.connect() for custom CAs, client certs, or SNI overrides (see TLS Support)nodes: MemcacheNode[] (readonly)Returns the list of all MemcacheNode instances in the cluster.
nodeIds: string[] (readonly)Returns the list of node IDs (e.g., ["localhost:11211", "127.0.0.1:11212"]).
hash: HashProviderGet or set the hash provider used for consistent hashing distribution.
timeout: numberGet or set the timeout for operations in milliseconds (default: 5000).
keepAlive: booleanGet or set the keepAlive setting. Updates all existing nodes. Requires reconnect() to apply changes.
keepAliveDelay: numberGet or set the keep alive delay in milliseconds. Updates all existing nodes. Requires reconnect() to apply changes.
retries: numberGet or set the number of retry attempts for failed commands (default: 0).
retryDelay: numberGet or set the base delay in milliseconds between retry attempts (default: 100).
retryBackoff: RetryBackoffFunctionGet or set the backoff function for calculating retry delays.
retryOnlyIdempotent: booleanGet or set whether retries are restricted to idempotent commands only (default: true).
maxKeySize: numberGet or set the maximum allowed key size in characters (default: 250). Memcache protocol max is 250.
maxValueSize: numberGet or set the maximum allowed value size in bytes (default: 1048576). Writes (set, add, replace, append, prepend, cas) throw when the encoded value exceeds this limit. Raise it if your memcached server is started with a larger -I item size.
maxExpiration: numberGet or set the maximum allowed expiration in seconds (default: 2592000). Writes that accept an expiration (set, add, replace, cas, touch) throw when exptime exceeds this limit. 0 (no expiration) is always allowed. Memcached treats any exptime greater than 2592000 as an absolute Unix timestamp, so the default guards against accidentally setting a TTL that memcached interprets as "already expired." Raise this if you need to pass Unix timestamps.
hashLargeKey: booleanGet or set whether keys exceeding maxKeySize are hashed instead of throwing (default: false). When enabled, oversized keys are replaced with a short, deterministic hex digest (via the hashery library, djb2 by default) before being sent to memcache, so any string length is accepted. The same input always produces the same hashed key, but distinct long keys can collide. To change algorithm or providers, configure the hashery property.
const client = new Memcache({ hashLargeKey: true });
const longKey = 'user:profile:' + 'x'.repeat(500);
await client.set(longKey, 'value'); // hashed automatically
await client.get(longKey); // same hash, returns 'value'
hashery: HasheryGet or set the Hashery instance used to hash oversized keys when hashLargeKey is enabled. Always returns an instance, even when hashing is disabled, so you can pre-configure it (algorithm, custom providers, caching) before flipping hashLargeKey on. Hashery is re-exported from this package for convenience.
import Memcache, { Hashery } from 'memcache';
// Simple — defaults to djb2 sync hashing
const simple = new Memcache({ hashLargeKey: true });
// Advanced — supply a Hashery preconfigured for fnv1
const advanced = new Memcache({
hashLargeKey: new Hashery({ defaultAlgorithmSync: 'fnv1' }),
});
// Or mutate the instance after construction
simple.hashery.defaultAlgorithmSync = 'murmur';
lazyConnect: boolean (readonly)Whether nodes defer connecting until the first command is executed (default: true).
connect(nodeId?: string): PromiseConnect to all Memcache servers or a specific node.
disconnect(): PromiseDisconnect all connections.
reconnect(): PromiseReconnect all nodes by disconnecting and connecting them again.
quit(): PromiseQuit all connections gracefully.
isConnected(): booleanCheck if any node is connected to a Memcache server.
getNodes(): MemcacheNode[]Get an array of all MemcacheNode instances.
getNode(id: string): MemcacheNode | undefinedGet a specific node by its ID (e.g., "localhost:11211").
addNode(uri: string | MemcacheNode, weight?: number): PromiseAdd a new node to the cluster. Throws error if node already exists.
removeNode(uri: string): PromiseRemove a node from the cluster.
getNodesByKey(key: string): PromiseGet the nodes for a given key using consistent hashing. Automatically connects to nodes if not already connected.
parseUri(uri: string): { host: string; port: number; secure?: boolean }Parse a URI string into host and port. Supports formats:
"localhost:11211" or "localhost""memcache://localhost:11211", "tcp://localhost:11211""memcaches://localhost:11211" (secure: true; enables TLS for that node)"[::1]:11211" or "memcache://[2001:db8::1]:11212""/var/run/memcached.sock" or "unix:///var/run/memcached.sock"get(key: string): PromiseGet a value from the Memcache server. Returns the first successful result from replica nodes.
gets(keys: string[]): PromiseGet multiple values from the Memcache server. Returns a Map with keys to values.
set(key: string, value: string, exptime?: number, flags?: number): PromiseSet a value in the Memcache server. Returns true only if all replica nodes succeed.
exptime - Expiration time in seconds (default: 0 = never expire)flags - Flags/metadata (default: 0)add(key: string, value: string, exptime?: number, flags?: number): PromiseAdd a value (only if key doesn't exist). Returns true only if all replica nodes succeed.
replace(key: string, value: string, exptime?: number, flags?: number): PromiseReplace a value (only if key exists). Returns true only if all replica nodes succeed.
cas(key: string, value: string, casToken: string, exptime?: number, flags?: number): PromiseCheck-And-Set: Store a value only if it hasn't been modified since last fetch. Returns true only if all replica nodes succeed.
append(key: string, value: string): PromiseAppend a value to an existing key. Returns true only if all replica nodes succeed.
prepend(key: string, value: string): PromisePrepend a value to an existing key. Returns true only if all replica nodes succeed.
delete(key: string): PromiseDelete a value from the Memcache server. Returns true only if all replica nodes succeed.
touch(key: string, exptime: number): PromiseUpdate expiration time without retrieving value. Returns true only if all replica nodes succeed.
incr(key: string, value?: number): PromiseIncrement a value. Returns the new value or undefined on failure.
value - Amount to increment (default: 1)decr(key: string, value?: number): PromiseDecrement a value. Returns the new value or undefined on failure.
value - Amount to decrement (default: 1)flush(delay?: number): PromiseFlush all values from all Memcache servers. Returns true if all nodes successfully flushed.
delay - Optional delay in seconds before flushingstats(type?: string): PromiseGet statistics from all Memcache servers. Returns a Map of node IDs to their stats.
version(): PromiseGet the Memcache server version from all nodes. Returns a Map of node IDs to version strings.
validateKey(key: string): voidValidates a Memcache key according to protocol requirements. Throws error if:
resolveKey(key: string): stringReturns the key that will actually be sent to memcache. When hashLargeKey is true and the key length exceeds maxKeySize, returns a short hex digest produced by the configured hashery instance (djb2 by default — 8 hex chars). Otherwise returns the original key unchanged. Called automatically before validateKey in every command, so calling it manually is only needed when you want to inspect the on-wire key.
createNode(host: string, port: number, options?: MemcacheNodeOptions): MemcacheNodeFactory function to create a new MemcacheNode instance.
import { createNode } from 'memcache';
const node = createNode('localhost', 11211, {
timeout: 5000,
keepAlive: true,
weight: 1
});
The Memcache client extends Hookified to provide powerful hooks and events for monitoring and customizing behavior.
The client emits various events during operations that you can listen to:
const client = new Memcache();
// Connection events
client.on('connect', () => {
console.log('Connected to Memcache server');
});
client.on('close', () => {
console.log('Connection closed');
});
client.on('error', (error) => {
console.error('Error:', error);
});
client.on('timeout', () => {
console.log('Connection timeout');
});
// Cache hit/miss events
client.on('hit', (key, value) => {
console.log(`Cache hit for key: ${key}`);
});
client.on('miss', (key) => {
console.log(`Cache miss for key: ${key}`);
});
connect - Emitted when connection to Memcache server is establishedclose - Emitted when connection is closederror - Emitted when an error occurstimeout - Emitted when a connection timeout occurshit - Emitted when a key is found in cache (includes key and value)miss - Emitted when a key is not found in cachequit - Emitted when quit command is sentwarn - Emitted for warning messagesinfo - Emitted for informational messagesautoDiscover - Emitted on initial auto discovery with the cluster configautoDiscoverUpdate - Emitted when auto discovery detects a topology changeautoDiscoverError - Emitted when auto discovery encounters an errorHooks allow you to intercept and modify behavior before and after operations. Every operation supports before and after hooks.
const client = new Memcache();
// Add a before hook for get operations
client.onHook('before:get', async ({ key }) => {
console.log(`Getting key: ${key}`);
});
// Add an after hook for set operations
client.onHook('after:set', async ({ key, value, success }) => {
if (success) {
console.log(`Successfully set ${key}`);
}
});
// Hooks can be async and modify behavior
client.onHook('before:set', async ({ key, value }) => {
console.log(`About to set ${key} = ${value}`);
// Perform validation, logging, etc.
});
All operations support before and after hooks with specific parameters:
before:get - { key }after:get - { key, value } (value is array or undefined)before:set - { key, value, exptime, flags }after:set - { key, value, exptime, flags, success }before:gets - { keys }after:gets - { keys, values } (values is a Map)before:add - { key, value, exptime, flags }after:add - { key, value, exptime, flags, success }before:replace - { key, value, exptime, flags }after:replace - { key, value, exptime, flags, success }before:append - { key, value }after:append - { key, value, success }before:prepend - { key, value }after:prepend - { key, value, success }before:delete - { key }after:delete - { key, success }before:incr - { key, value }after:incr - { key, value, newValue }before:decr - { key, value }after:decr - { key, value, newValue }before:touch - { key, exptime }after:touch - { key, exptime, success }const client = new Memcache();
// Log all get operations
client.onHook('before:get', async ({ key }) => {
console.log(`[GET] Fetching key: ${key}`);
});
client.onHook('after:get', async ({ key, value }) => {
console.log(`[GET] Key: ${key}, Found: ${value !== undefined}`);
});
// Log all set operations with timing
client.onHook('before:set', async (context) => {
context.startTime = Date.now();
});
client.onHook('after:set', async (context) => {
const duration = Date.now() - context.startTime;
console.log(`[SET] Key: ${context.key}, Success: ${context.success}, Time: ${duration}ms`);
});
Memcache supports pluggable distribution algorithms to determine how keys are distributed across nodes. You can configure the algorithm using the hash option.
KetamaHash uses the Ketama consistent hashing algorithm, which minimizes key redistribution when nodes are added or removed. This is the default and recommended algorithm for production environments with dynamic scaling.
import { Memcache } from 'memcache';
// KetamaHash is used by default
const client = new Memcache({
nodes: ['server1:11211', 'server2:11211', 'server3:11211']
});
Characteristics:
ModulaHash uses a simple modulo-based hashing algorithm (hash(key) % nodeCount). This is a simpler algorithm that may redistribute all keys when nodes change.
import { Memcache, ModulaHash } from 'memcache';
// Use ModulaHash for distribution
const client = new Memcache({
nodes: ['server1:11211', 'server2:11211', 'server3:11211'],
hash: new ModulaHash()
});
// With a custom hash algorithm (default is sha1)
const client2 = new Memcache({
nodes: ['server1:11211', 'server2:11211'],
hash: new ModulaHash('md5')
});
Characteristics:
ModulaHash supports weighted nodes, where nodes with higher weights receive proportionally more keys:
import { Memcache, ModulaHash, createNode } from 'memcache';
// Create nodes with different weights
const node1 = createNode('server1', 11211, { weight: 3 }); // 3x traffic
const node2 = createNode('server2', 11211, { weight: 1 }); // 1x traffic
const client = new Memcache({
nodes: [node1, node2],
hash: new ModulaHash()
});
// server1 will receive approximately 75% of keys
// server2 will receive approximately 25% of keys
BroadcastHash sends every operation to all nodes in the cluster. Instead of partitioning keys across nodes, every getNodesByKey() call returns all nodes, so reads and writes are broadcast to every server.
import { Memcache, BroadcastHash } from 'memcache';
// Use BroadcastHash for full replication
const client = new Memcache({
nodes: ['server1:11211', 'server2:11211', 'server3:11211'],
hash: new BroadcastHash()
});
// Every set/get/delete hits all three nodes
await client.set('mykey', 'Hello!');
Characteristics:
| Feature | KetamaHash | ModulaHash | BroadcastHash |
|---|---|---|---|
| Key redistribution on node change | Minimal (~1/n keys) | All keys may move | N/A (all nodes always) |
| Complexity | Higher (virtual nodes) | Lower (simple modulo) | Simplest |
| Performance | Slightly slower | Faster | Depends on node count |
| Best for | Dynamic scaling | Fixed clusters | Replication |
| Weighted nodes | Yes | Yes | No |
Use KetamaHash (default) when:
Use ModulaHash when:
Use BroadcastHash when:
The Memcache client supports automatic retry of failed commands with configurable backoff strategies.
Enable retries by setting the retries option:
import { Memcache } from 'memcache';
const client = new Memcache({
nodes: ['localhost:11211'],
retries: 3, // Retry up to 3 times
retryDelay: 100 // 100ms between retries
});
You can also modify retry settings at runtime:
client.retries = 5;
client.retryDelay = 200;
The client includes two built-in backoff functions:
import { Memcache, defaultRetryBackoff } from 'memcache';
const client = new Memcache({
retries: 3,
retryDelay: 100,
retryBackoff: defaultRetryBackoff // 100ms, 100ms, 100ms
});
import { Memcache, exponentialRetryBackoff } from 'memcache';
const client = new Memcache({
retries: 3,
retryDelay: 100,
retryBackoff: exponentialRetryBackoff // 100ms, 200ms, 400ms
});
You can provide your own backoff function:
const client = new Memcache({
retries: 3,
retryDelay: 100,
retryBackoff: (attempt, baseDelay) => {
// Exponential backoff with jitter
const delay = baseDelay * Math.pow(2, attempt);
return delay + Math.random() * delay * 0.1;
}
});
The backoff function receives:
attempt - The current attempt number (0-indexed)baseDelay - The configured retryDelay valueImportant: By default, retries are only performed for commands explicitly marked as idempotent. This prevents accidental double-execution of non-idempotent operations like incr, decr, append, and prepend.
If a network timeout occurs after the server applies a mutation but before the client receives the response, retrying would apply the mutation twice:
For read operations (always safe to retry):
// Mark read operations as idempotent
await client.execute('get mykey', nodes, { idempotent: true });
For idempotent writes (safe to retry):
// SET with the same value is idempotent
await client.execute('set mykey 0 0 5\r\nhello', nodes, { idempotent: true });
Disable safety for all commands (use with caution):
const client = new Memcache({
retries: 3,
retryOnlyIdempotent: false // Allow retries for ALL commands
});
retryOnlyIdempotent |
idempotent flag |
Retries enabled? |
|---|---|---|
true (default) |
false (default) |
No |
true (default) |
true |
Yes |
false |
(any) | Yes |
The following methods do not use the retry mechanism and have their own error handling:
get() - Returns undefined on failuregets() - Returns partial results on node failureflush() - Operates directly on nodesstats() - Operates directly on nodesversion() - Operates directly on nodesTo use retries with read operations, use the execute() method directly:
const nodes = await client.getNodesByKey('mykey');
const results = await client.execute('get mykey', nodes, { idempotent: true });
The Memcache client supports SASL (Simple Authentication and Security Layer) authentication using the PLAIN mechanism. This allows you to connect to memcached servers that require authentication.
import { Memcache } from 'memcache';
const client = new Memcache({
nodes: ['localhost:11211'],
sasl: {
username: 'myuser',
password: 'mypassword',
},
});
await client.connect();
// Client is now authenticated and ready to use
The sasl option accepts an object with the following properties:
username: string - The username for authentication (required)password: string - The password for authentication (required)mechanism?: 'PLAIN' - The SASL mechanism to use (default: 'PLAIN')Currently, only the PLAIN mechanism is supported.
Important: Memcached servers with SASL enabled (-S flag) require the binary protocol for all operations after authentication. The standard text-based methods (client.get(), client.set(), etc.) will not work on SASL-enabled servers.
Use the binary* methods on nodes for SASL-enabled servers:
import { Memcache } from 'memcache';
const client = new Memcache({
nodes: ['localhost:11211'],
sasl: { username: 'user', password: 'pass' },
});
await client.connect();
// Access the node directly for binary operations
const node = client.nodes[0];
// Binary protocol operations
await node.binarySet('mykey', 'myvalue', 3600); // Set with 1 hour expiry
const value = await node.binaryGet('mykey'); // Get value
await node.binaryDelete('mykey'); // Delete key
// Other binary operations
await node.binaryAdd('newkey', 'value'); // Add (only if not exists)
await node.binaryReplace('existingkey', 'newvalue'); // Replace (only if exists)
await node.binaryIncr('counter', 1); // Increment
await node.binaryDecr('counter', 1); // Decrement
await node.binaryAppend('mykey', '-suffix'); // Append to value
await node.binaryPrepend('mykey', 'prefix-'); // Prepend to value
await node.binaryTouch('mykey', 7200); // Update expiration
await node.binaryFlush(); // Flush all
const version = await node.binaryVersion(); // Get server version
const stats = await node.binaryStats(); // Get server stats
You can also configure SASL credentials when creating individual nodes:
import { createNode } from 'memcache';
// Create a node with SASL credentials
const node = createNode('localhost', 11211, {
sasl: { username: 'user', password: 'pass' },
});
// Connect and use binary methods
await node.connect();
await node.binarySet('mykey', 'hello');
const value = await node.binaryGet('mykey');
You can listen for authentication events on both nodes and the client:
import { Memcache, MemcacheNode } from 'memcache';
// Node-level events
const node = new MemcacheNode('localhost', 11211, {
sasl: { username: 'user', password: 'pass' },
});
node.on('authenticated', () => {
console.log('Node authenticated successfully');
});
node.on('error', (error) => {
if (error.message.includes('SASL authentication failed')) {
console.error('Authentication failed:', error.message);
}
});
await node.connect();
// Client-level events (forwarded from nodes)
const client = new Memcache({
nodes: ['localhost:11211'],
sasl: { username: 'user', password: 'pass' },
});
client.on('authenticated', () => {
console.log('Client authenticated');
});
await client.connect();
node.hasSaslCredentials - Returns true if SASL credentials are configurednode.isAuthenticated - Returns true if the node has successfully authenticatedTo use SASL authentication, your memcached server must be configured with SASL support:
Build memcached with SASL support - Ensure memcached was compiled with --enable-sasl
Create SASL users - Use saslpasswd2 to create users:
saslpasswd2 -a memcached -c username
Configure SASL mechanism - Create /etc/sasl2/memcached.conf:
mech_list: plain
Start memcached with SASL - Use the -S flag:
memcached -S -m 64 -p 11211
For more details, see the memcached SASL documentation.
The Memcache client supports AWS ElastiCache Auto Discovery, which automatically detects cluster topology changes and adds or removes nodes as needed. When enabled, the client connects to a configuration endpoint, retrieves the current list of cache nodes, and periodically polls for changes.
import { Memcache } from 'memcache';
const client = new Memcache({
nodes: [],
autoDiscover: {
enabled: true,
configEndpoint: 'my-cluster.cfg.use1.cache.amazonaws.com:11211',
},
});
await client.connect();
// The client automatically discovers and connects to all cluster nodes
If you omit configEndpoint, the first node in the nodes array is used as the configuration endpoint:
const client = new Memcache({
nodes: ['my-cluster.cfg.use1.cache.amazonaws.com:11211'],
autoDiscover: {
enabled: true,
},
});
The autoDiscover option accepts an object with the following properties:
enabled: boolean - Enable auto discovery of cluster nodes (required)pollingInterval?: number - How often to poll for topology changes, in milliseconds (default: 60000)configEndpoint?: string - The configuration endpoint to use for discovery. This is typically the .cfg endpoint from ElastiCache. If not specified, the first node in the nodes array will be useduseLegacyCommand?: boolean - Use the legacy get AmazonElastiCache:cluster command instead of config get cluster (default: false)The client emits events during the auto discovery lifecycle:
const client = new Memcache({
nodes: [],
autoDiscover: {
enabled: true,
configEndpoint: 'my-cluster.cfg.use1.cache.amazonaws.com:11211',
},
});
// Emitted on initial discovery with the full cluster config
client.on('autoDiscover', (config) => {
console.log('Discovered nodes:', config.nodes);
console.log('Config version:', config.version);
});
// Emitted when polling detects a topology change
client.on('autoDiscoverUpdate', (config) => {
console.log('Cluster topology changed:', config.nodes);
});
// Emitted when discovery encounters an error (non-fatal, retries on next poll)
client.on('autoDiscoverError', (error) => {
console.error('Discovery error:', error.message);
});
await client.connect();
For ElastiCache engine versions older than 1.4.14, use the legacy discovery command:
const client = new Memcache({
nodes: [],
autoDiscover: {
enabled: true,
configEndpoint: 'my-cluster.cfg.use1.cache.amazonaws.com:11211',
useLegacyCommand: true, // Uses 'get AmazonElastiCache:cluster' instead of 'config get cluster'
},
});
The Memcache client fully supports IPv6 addresses using standard bracket notation in URIs.
import { Memcache } from 'memcache';
// IPv6 loopback
const client = new Memcache('[::1]:11211');
// Multiple IPv6 nodes
const client = new Memcache({
nodes: [
'[::1]:11211',
'[2001:db8::1]:11211',
'memcache://[2001:db8::2]:11212',
],
});
await client.connect();
When auto discovery returns IPv6 node addresses, the client automatically brackets them for correct URI handling:
const client = new Memcache({
nodes: [],
autoDiscover: {
enabled: true,
configEndpoint: '[2001:db8::1]:11211',
},
});
await client.connect();
// Discovered IPv6 nodes are added as [host]:port automatically
Node IDs for IPv6 addresses use bracket notation to avoid ambiguity:
const client = new Memcache({
nodes: ['[::1]:11211', '[2001:db8::1]:11212'],
});
console.log(client.nodeIds);
// ['[::1]:11211', '[2001:db8::1]:11212']
The client can connect to TLS-enabled memcached servers (memcached ships TLS
since 1.5.13 via -Z; the official Docker image supports it since 1.5.21).
Connection readiness waits for the completed TLS handshake (secureConnect),
so pipelined commands are never written into an unfinished handshake.
Enable TLS for every node with the client-level tls option:
import { Memcache } from 'memcache';
// TLS with Node's default trust store (publicly-trusted server certs)
const client = new Memcache({
nodes: ['my-cache.example.com:11211'],
tls: true,
});
await client.set('mykey', 'Hello over TLS!');
Or per node with the memcaches:// URI scheme (enables TLS for that node
even when the client-level option is unset):
const client = new Memcache('memcaches://my-cache.example.com:11211');
ElastiCache Serverless (Memcached) requires TLS and only speaks the text
protocol — both are this client's defaults, so the only configuration needed
is tls: true (the server presents a publicly-trusted ACM certificate):
const client = new Memcache({
nodes: ['my-cache-xxxxxx.serverless.use1.cache.amazonaws.com:11211'],
tls: true,
});
Pass any tls.connect() options — private CAs, client certificates, servername
overrides — as an object:
import { readFileSync } from 'node:fs';
const client = new Memcache({
nodes: ['memcached-internal:11211'],
tls: {
ca: readFileSync('/etc/ssl/private-ca.pem'),
// cert, key, servername, ... are passed through to tls.connect()
},
});
Notes:
tls: true / tls: {} both enable TLS with default trust; certificate
verification is always on (standard Node behavior). To connect to a server
with a self-signed cert, pass its CA — do not disable verification.node.uri uses memcaches:// when TLS is enabled, so passing it back into
addNode() or the constructor keeps TLS on even without a client-level
tls option.These are provided to show a simple benchmark against current libraries. This is not robust but it is something we update regularly to make sure we are keeping performant.
| name | summary | ops/sec | time/op | margin | samples |
|---|---|---|---|---|---|
| memcache set/get (v1.4.0) | 🥇 | 3K | 350µs | ±0.19% | 10K |
| memcached set/get (v2.2.2) | -2.9% | 3K | 361µs | ±0.16% | 10K |
| memjs set/get (v1.3.2) | -12% | 3K | 398µs | ±0.17% | 10K |
Please read our Contributing Guidelines and also our Code of Conduct.
Adds TLS connections (`tls` / `memcaches://`), publishes memcachejs.org, and hardens CI/publish.
add TLS support (`7a822b9`, #115)
```javascript
import { Memcache } from 'memcache';
const client = new Memcache({
nodes: ['my-cache.example.com:11211'],
tls: true, // or a tls.ConnectionOptions object, e.g. { ca }
});
```
```javascript
// Per-node TLS without a client-level tls option
const client = new Memcache('memcaches://my-cache.example.com:11211');
```
generate memcachejs.org site with Docula (`1f0507e`, #104)
Full diff: https://github.com/jaredwray/memcache/compare/v1.9.0...v1.10.0
Maintenance release: dependency and CI upgrades. Minimum supported Node is now 22.19.
Full diff: https://github.com/jaredwray/memcache/compare/v1.8.0...v1.9.0
Maintenance release: dependency, build, and CI upgrades. Minimum supported Node is now 22.
Full diff: https://github.com/jaredwray/memcache/compare/v1.7.0...v1.8.0