- 
                Notifications
    
You must be signed in to change notification settings  - Fork 112
 
NodeJS wrapper
Valkey GLIDE provides support for both Cluster and Standalone and configurations. Please refer to the relevant section based on your specific setup.
Valkey GLIDE supports Cluster deployments, where the database is partitioned across multiple primary shards, with each shard being represented by a primary node and zero or more replica nodes.
To initialize a GlideClusterClient, you need to provide a GlideClusterClientConfiguration that includes the addresses of initial seed nodes. Valkey GLIDE automatically discovers the entire cluster topology, eliminating the necessity of explicitly listing all cluster nodes.
The NodeAddress class represents the host and port of a cluster node. The host can be either an IP address, a hostname, or a fully qualified domain name (FQDN).
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses
});In the cluster, data is divided into slots, and each primary node within the cluster is responsible for specific slots. Valkey GLIDE adheres to Valkey OSS guidelines when determining the node(s) to which a command should be sent in clustering mode.
For more details on the routing of specific commands, please refer to the documentation within the code.
When requests are dispatched to multiple shards in a cluster (as discussed in the Request routing section), the client needs to aggregate the responses for a given command. Valkey GLIDE follows Valkey OSS guidelines for determining how to aggregate the responses from multiple shards within a cluster.
To learn more about response aggregation for specific commands, please refer to the documentation within the code.
The cluster's topology can change over time. New nodes can be added or removed, and the primary node owning a specific slot may change. Valkey GLIDE is designed to automatically rediscover the topology whenever the server indicates a change in slot ownership. This ensures that the Valkey GLIDE client stays in sync with the cluster's topology.
Valkey GLIDE also supports Standalone deployments, where the database is hosted on a single primary node, optionally with replica nodes. To initialize a GlideClient for a standalone setup, you should create a GlideClientConfiguration that includes the addresses of primary and all replica nodes.
import {GlideClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "primary.example.com",
        port: 6379
    },
    {
        host: "replica1.example.com",
        port: 6379
    },
    {
        host: "replica2.example.com",
        port: 6379
    },
];
const client = await GlideClient.createClient({
    addresses: addresses
});For information on the supported commands and their corresponding parameters, we recommend referring to the documentation in the code. This documentation provides in-depth insights into the usage and options available for each command.
Valkey strings are stored in its simplest form: as a sequence of bytes. GLIDE offers GlideString which maps to Valkey strings. Use it to pass Valkey strings as arguments to commands, or receive Valkey strings in response to commands. GlideString represents either:
- 
string: as a UTF-8 encoded string. - 
Buffer: as abyte[]. 
The return types of command API:
- Command uses 
stringinstead ofGlideStringas the return type if it contains a simple string value (simple strings in Valkey are always UTF-8 encoded strings). For example,typecommand returns one of pre-defined strings, orsetcommand which returns"OK". - Command uses 
Bufferas the return type, because it always contains binary data. For example,dumpandfunctionDumpcommands. - Most commands use 
GlideStringas the common return type. 
In Node.js, most users expect the responses to be in string format unless specified otherwise. Users can select which data type they expect to receive as a response. The user has the option, using DecoderOption as an extension to command option types with Decoder, of converting the response into either a string or bytes for each command. In addition, as part of the client creation process, the user has the option of setting a default for all commands if no decoder argument is passed to the command.
Decoder is an optional parameter for all commands and it has two options
- 
Bytes: decodes the response into aBuffer(byte array). - 
String: decodes the response into a string. 
If Decoder is not configured, Decoder.String will be used as the default decoder.
Note: Using the Decoder.String to convert Non-UTF-8 encoded Valkey strings can lead to errors unrecoverable data lost. See: #2221.
Here is an example of command implementation to outline arguments using DecoderOption and response type:
public getdel(
        key: GlideString,
        options?: DecoderOption,
    ): Promise<GlideString | null>Here's a simple example demonstrating how to use Decoder in command API and Buffer.from() to encode binary data:
expect(await client.set(key, value)).toEqual("OK");
expect(await client.getdel(key)).toEqual(value);
const valueEncoded = Buffer.from(value);
expect(await client.set(key, value)).toEqual("OK");
expect(await client.getdel(key, { decoder: Decoder.Bytes })).toEqual(
    valueEncoded,
);In Valkey Glide 2.0, the concept of Batch and ClusterBatch replaces the previous Transaction and ClusterTransaction APIs. This change provides greater flexibility by supporting both atomic batches (Transactions) and non-atomic batches (Pipelining), while ensuring easy configuration and clear, detailed examples for each scenario.
Glide 2.0 introduces a robust Batch API with two primary modes:
- Atomic Batch: Guarantees that all commands in a batch execute as a single, atomic unit. No other commands can interleave (similar to MULTI/EXEC).
 - Non-Atomic Batch (Pipeline): Sends multiple commands in one request without atomic guarantees. Commands can span multiple slots/nodes in a cluster and do not block other operations from being processed between them.
 
Both modes leverage the same classes— Batch for standalone mode and ClusterBatch for cluster mode — distinguished by an isAtomic flag. Extra configuration is provided via BatchOptions or ClusterBatchOptions, allowing control over timeouts, routings, and retry strategies.
Atomic Batch (Transaction)
- Definition: A set of commands executed together as a single, indivisible operation.
 - Guarantees: Sequential execution without interruption. Other clients cannot interleave commands between the batched operations.
 - Slot Constraint (Cluster Mode): When running against a cluster, all keys in an atomic batch must map to the same hash slot. Mixing keys from different slots will cause the transaction to fail.
 - 
Underlying Valkey: Equivalent to 
MULTI/EXECValkey commands. - Use Case: When you need consistency and isolation.
 - See: Valkey Transactions.
 
Non-Atomic Batch (Pipeline)
- Definition: A group of commands sent in a single request, but executed without atomicity or isolation.
 - Behavior: Commands may be processed on different slots/nodes (in cluster mode), and other operations from different clients may interleave during execution.
 - Underlying Valkey: Similar to pipelining, minimizing round-trip latencies by sending all commands at once.
 - Use Case: Bulk reads or writes where each command is independent.
 - See: Valkey Pipelines.
 
Batch
For standalone (non-cluster, cluster mode disabled) clients.
import {Batch} from "@valkey/valkey-glide";
// Create an atomic batch (transaction)
const batch = new Batch(true)
// Create a non-atomic batch (pipeline)
const batch = new Batch(false)Note: Standalone Batches are executed on primary node.
ClusterBatch
For cluster (cluster mode enabled) clients (Mirrors Batch but routes commands based on slot ownership, splitting into sub-pipelines if needed, Read more in Multi-Node support).
import {ClusterBatch} from "@valkey/valkey-glide";
// Create an atomic cluster batch (must use keys mapping to same slot)
const batch = new ClusterBatch(true)
// Create a non-atomic cluster batch (pipeline may span multiple slots)
const batch = new ClusterBatch(false)Note: When
isAtomic = true, all keys in theClusterBatchmust map to the same slot. Attempting to include keys from different slots will result in an exception. Read more in Multi-Node support. If the client is configured to read from replicas (ReplicaPrefered, AZ_AFFINITY, AZ_AFFINITY_REPLICAS_AND_PRIMARY) read commands may be routed to the replicas, in a round robin manner, if this behavior impacts your application, consider creating a dedicated client, with the desired ReadFrom configuration.
Error handling - Raise on Error
Determines how errors are surfaced when calling exec(...). It is passed directly:
// Standalone Mode
public async exec(
    batch: Batch,
    raiseOnError: boolean,
    options?: BatchOptions & DecoderOption,
)
// Cluster Mode
public async exec(
    batch: ClusterBatch,
    raiseOnError: boolean,
    options?: ClusterBatchOptions & DecoderOption,
)Behavior:
- 
raiseOnError = true: When set totrue, the first encountered error within the batch (after all configured retries and redirections have been executed) is raised as aRequestException. - 
raiseOnError = false:- When set to 
false, errors are returned as part of the response array rather than thrown. - Each failed command’s error details appear as a 
RequestExceptioninstance in the corresponding position of the returned array. - Allows processing of both successful and failed commands together.
 
 - When set to 
 
Example:
// Cluster pipeline with raiseOnError = false
const batch = new ClusterBatch(false);
batch.set(key, "hello")     // OK
       .lpop(key)           // WRONGTYPE error (not a list)
       .del([key])          // 1
       .rename(key, key2);  // NO SUCH KEY error
       
const result = await GlideClusterClient.exec(batch, false);
console.log("Result is:", result);
// Output: Result is: [OK, RequestError: WRONGTYPE: Operation against a key holding the wrong kind of value, 1, RequestError: An error was signalled by the server: - ResponseError: no such key])// Transaction with raiseOnError = true
const batch = new Batch(true);
batch.set(key, "hello")     // OK
       .lpop(key)           // WRONGTYPE error (not a list)
       .del([key])          // 1
       .rename(key, key2);  // NO SUCH KEY error
       
try {
    await GlideClient.exec(batch, false);
} catch (error) {
    console.log("Batch execution aborted: ", error);
}
// Output: Batch execution aborted:  RequestError: WRONGTYPE: Operation against a key holding the wrong kind of valueBatchOptions
Configuration for standalone batches.
| Option | Type | Default | Description | 
|---|---|---|---|
timeout | 
Integer | 
Client-level request timeout (e.g., 5000 ms) | Maximum time in milliseconds to wait for the batch response. If exceeded, a timeout error is returned for the batch. | 
import {BatchOptions} from "@valkey/valkey-glide";
const options: BatchOptions = {
    timeout: 2000, // 2 seconds
};ClusterBatchOptions
Configuration for cluster batches.
| Option | Type | Default | Description | 
|---|---|---|---|
timeout | 
Integer | 
Client’s requestTimeout | Maximum time in milliseconds to wait for entire cluster batch response. | 
retryStrategy | 
ClusterBatchRetryStrategy | 
null (defaults to no retries) | Configures retry settings for server and connection errors. Not supported ifisAtomic = true — retry strategies only apply to non-atomic (pipeline) batches. | 
route | 
SingleNodeRoute | 
null | Configures single-node routing for the batch request. | 
ClusterBatchRetryStrategy
Defines retry behavior (only for non-atomic cluster batches).
| Option | Type | Default | Description | 
|---|---|---|---|
retryServerError | 
boolean | 
false | 
Retry commands that fail with retriable server errors (e.g.TRYAGAIN). May cause out-of-order results. | 
retryConnectionError | 
boolean | 
false | 
Retry entire batch on connection failures. May cause duplicate executions since server might have processed the request before failure. | 
import {ClusterBatchRetryStrategy} from "@valkey/valkey-glide";
const retryStrategy : ClusterBatchRetryStrategy = {
        retryServerError: false,
        retryConnectionError: false,
}Note: The ClusterBatchRetryStrategy configuration is only for non-atomic cluster batches, If provided for an atomic cluster batch (a cluster transaction), an error will be thrown.
Full usage
import {ClusterBatchOptions} from "@valkey/valkey-glide";
const options: ClusterBatchOptions = {
    timeout: 5000,                    // 5 seconds
    route: "randomNode",              // Route the batch to a random node
    retryStrategy: {
        retryServerError: true,       // Retry on server errors
        retryConnectionError: false,  // Do not retry on connection errors
    },
};Timeout
- Specifies the maximum time (in milliseconds) to wait for the batch (atomic or non-atomic) request to complete.
 - If the timeout is reached before receiving all responses, the batch fails with a timeout error.
 - Defaults to the client’s 
requestTimeoutif not explicitly set. 
Retry Strategies (Cluster Only, Non-Atomic Batches)
- 
Retry on Server Errors
- Applies when a command fails with a retriable server error (e.g., 
TRYAGAIN). - Glide will automatically retry the failed command on the same node or the new master, depending on the topology update.
 ⚠️ Caveat: Retried commands may arrive later than subsequent commands, leading to out-of-order execution if commands target the same slot.
 - Applies when a command fails with a retriable server error (e.g., 
 - 
Retry on Connection Errors
- If a connection error occurs, the entire batch (or sub-pipeline, Read more in Multi-Node support) is retried from the start.
 ⚠️ Caveat: If the server received and processed some or all commands before the connection failure, retrying the batch may lead to duplicate executions.
 
Route (Cluster Only)
Configures single-node routing for the batch request. The client will send the batch to the specified node defined by route.
If a redirection error occurs:
- For Atomic Batches (Transactions): The entire transaction will be redirected.
 - For Non-Atomic Batches (Pipelines): only the commands that encountered redirection errors will be redirected.
 
Standalone (Atomic Batch)
import { GlideClient, Batch, BatchOptions } from "@valkey/valkey-glide";
// Create client configuration
const addresses = [
    {
        host: "localhost",
        port: 6379,
    },
];
// Initialize client
const client = await GlideClient.createClient({ addresses: addresses });
// Configure batch options
const options : BatchOptions = {
    timeout: 2000  // 2-second timeout
};
// Create atomic batch (true indicates atomic/transaction mode)
const atomicBatch = new Batch(true)
    .set("account:source", "100")
    .set("account:dest", "0")
    .incrBy("account:dest", 50)
    .decrBy("account:source", 50)
    .get("account:source");
try {
    // Execute with raiseOnError = true
    const results = await client.exec(atomicBatch, true, options);
    console.log("Atomic Batch Results:", results);
    // Atomic Batch Results: ["OK", "OK", 50, 50, "50"]
} catch (e) {
    console.error("Batch failed:", e.message);Standalone (Non-Atomic Batch)
import { GlideClient, Batch, BatchOptions} from "@valkey/valkey-glide";
// Create client configuration
const addresses = [
  {
    host: "localhost",
    port: 6379,
  },
];
// Initialize client
const client = await GlideClient.createClient({ addresses: addresses });
// Configure batch options
const options : BatchOptions = {
  timeout: 2000  // 2-second timeout
};
// Create non-atomic batch (false indicates pipeline mode)
const pipeline = new Batch(false)
  .set("temp:key1", "value1")
  .set("temp:key2", "value2")
  .get("temp:key1")
  .get("temp:key2");
// Execute with raiseOnError = false
const results = await client.exec(pipeline, false, options);
console.log("Pipeline Results:", results);
// Pipeline Results: ["OK", "OK", "value1", "value2"]Cluster (Atomic Batch)
import { GlideClusterClient, ClusterBatch, ClusterBatchOptions } from "@valkey/valkey-glide";
// Initialize cluster client configuration
const addresses = [
    {
        host: "127.0.0.1",
        port: 6379
    }
];
// Initialize client
const glideClusterClient = await GlideClusterClient.createClient({ addresses: addresses });
// Configure atomic batch options
const options: ClusterBatchOptions = {
    timeout: 3000  // 3-second timeout
};
// Create atomic cluster batch (all keys map to same slot)
const atomicClusterBatch = new ClusterBatch(true)
    .set("user:100:visits", "1")    
    .incrBy("user:100:visits", 5)    
    .get("user:100:visits");
// Execute with raiseOnError = true
try {
    const clusterResults = await glideClusterClient.exec(atomicClusterBatch, true, options);
    console.log("Atomic Cluster Batch:", clusterResults);
    // Expected output: Atomic Cluster Batch: ["OK", 6, "6"]
} catch (e) {
    console.error("Atomic cluster batch failed:", e);
}Important: If you attempt to include keys from different slots, the batch creation will throw an exception informing you that keys must map to the same slot when
isAtomic = true.
Cluster (Non-Atomic Batch / Pipeline)
import { GlideClusterClient, ClusterBatch, ClusterBatchOptions, ClusterBatchRetryStrategy } from "@valkey/valkey-glide";
// Initialize cluster client configuration
const addresses = [
    {
        host: "localhost",
        port: 6379
    }
];
// Initialize client
const glideClusterClient = await GlideClusterClient.createClient({ addresses : addresses });
// Configure retry strategy and pipeline options
const retryStrategy : ClusterBatchRetryStrategy = {
    retryServerError: false,
    retryConnectionError: true
};
const pipelineOptions : ClusterBatchOptions = {
    timeout: 5000,                // 5-second timeout
    retryStrategy: retryStrategy
};
// Create pipeline spanning multiple slots
const pipelineCluster = new ClusterBatch(false)  // false indicates non-atomic (pipeline)
    .set("page:home:views", "100")
    .incrBy("page:home:views", 25)
    .get("page:home:views")
    .lpush("recent:logins", ["user1"])
    .lpush("recent:logins", ["user2"])
    .lrange("recent:logins", 0, 1);
// Execute with raiseOnError = false
const pipelineResults = await glideClusterClient.exec(pipelineCluster, false, pipelineOptions);
console.log("Pipeline Cluster Results:", pipelineResults);
// Expected output: Pipeline Cluster Results: ["OK", 125, "125", 1, 2, ["user2", "user1"]]While atomic batches (transactions) are restricted to a single Valkey node— all commands must map to the same hash slot in cluster mode—non-atomic batches (pipelines) can span multiple nodes. This enables operations that involve keys located in different slots or even multi-node commands.
When Glide processes a pipeline:
- 
Slot Calculation and Routing: For each key-based command (e.g., 
GET,SET), Glide computes the hash slot and determines which node owns that slot. If a command does not reference a key (e.g.,INFO), it follows the command’s default request policy. - Grouping into Sub-Pipelines: Commands targeting the same node are grouped together into a sub-pipeline. Each sub-pipeline contains all commands destined for a specific node.
 - Dispatching Sub-Pipelines: Glide sends each sub-pipeline independently to its target node as a pipelined request.
 - Aggregating Responses: Once all sub-pipelines return their results, Glide reassembles the responses into a single array, preserving the original command order. Multi-node commands are automatically split and dispatched appropriately.
 
Retry Strategy in Pipelines
When errors occur during pipeline execution, Glide handles them efficiently and granularly — each command in the pipeline receives its own response, whether successful or not. This means pipeline execution is not all-or-nothing: some commands may succeed while others may return errors (See the ClusterBatchRetryStrategy configuration and error handling details in the classes and API section for how to handle these errors programmatically).
Glide distinguishes between different types of errors and handles them as follows:
- 
Redirection Errors (e.g., 
MOVEDorASK): These are always handled automatically. Glide will update the topology map if needed and redirect the command to the appropriate node, regardless of the retry configuration. - 
Retriable Server Errors (e.g., 
TRYAGAIN): If theretryServerErroroption is enabled in the batch's retry strategy, Glide will retry commands that fail with retriable server errors.
⚠️ Retrying may cause out-of-order execution for commands targeting the same slot. - 
Connection Errors:
If the 
retryConnectionErroroption is enabled, Glide will retry the batch if a connection failure occurs.
⚠️ Retrying after a connection error may result in duplicate executions, since the server might have already received and processed the request before the error occurred. 
Retry strategies are currently supported only for non-atomic (pipeline) cluster batches. You can configure these using the ClusterBatchRetryStrategy options:
- 
retryServerError:Retry on server errors. - 
retryConnectionError:Retry on connection failures. 
Example Scenario:
Suppose you issue the following commands:
MGET key {key}:1
SET key "value"
When keys are empty, the result is expected to be:
[null, null]
OK
However, suppose the slot of key is migrating. In this case, both commands will return an ASK error and be redirected.
Upon ASK redirection, a multi-key command (like MGET) may return a TRYAGAIN error (triggering a retry), while the SET command succeeds immediately.
This can result in an unintended reordering of commands if the first command is retried after the slot stabilizes:
["value", null]
OK
- 
Deprecated Classes:
TransactionandClusterTransactionare deprecated in Glide 2.0. - 
Replacement: Use
BatchorClusterBatchwithisAtomic = trueto achieve transaction-like (atomic) behavior. - 
Migration Tips:
- Replace calls to 
new Transaction()withnew Batch(true). - Replace calls to 
new ClusterTransaction()withnew ClusterBatch(true). - Replace 
client.exec(transaction)withclient.exec(batch, raiseOnError)orclient.exec(batch, raiseOnError, options). 
 - Replace calls to 
 
Observability is consistently one of the top feature requests by customers. Valkey GLIDE 2.0 introduces support for OpenTelemetry (OTel), enabling developers to gain deep insights into client-side performance and behavior in distributed systems. OTel is an open source, vendor-neutral framework that provides APIs, SDKs, and tools for generating, collecting, and exporting telemetry data—such as traces, metrics, and logs. It supports multiple programming languages and integrates with various observability backends like Prometheus, Jaeger, and AWS CloudWatch.
GLIDE's OpenTelemetry integration is designed to be both powerful and easy to adopt. Once an OTel collector endpoint is configured, GLIDE begins emitting default metrics and traces automatically—no additional code changes are required. This simplifies the path to observability best practices and minimizes disruption to existing workflows.
GLIDE emits several built-in metrics out of the box. These metrics can be used to build dashboards, configure alerts, and monitor performance trends:
- Timeouts: Number of requests that exceeded their timeout duration.
 - Retries: Count of operations retried due to transient errors or topology changes.
 - Moved Errors: Number of MOVED responses received, indicating key reallocation in the cluster.
 
These metrics are emitted to your configured OpenTelemetry collector and can be viewed in any supported backend (Prometheus, CloudWatch, etc.).
GLIDE creates a trace span for each Valkey command, giving detailed visibility into client-side performance. Each trace captures:
- The entire command lifecycle: from creation to completion or failure.
 - A nested 
send_commandspan, measuring communication time with the Valkey server. - A status tag indicating success or error for each span, helping you identify failure patterns.
 
This distinction helps developers separate client-side queuing latency from server communication delays, making it easier to troubleshoot performance issues.
⚠ Note: Some advanced commands are not yet included in tracing instrumentation:
- The SCAN family of commands (SCAN, SSCAN, HSCAN, ZSCAN)
 - Lua scripting commands (EVAL, EVALSHA)
 
Support for these commands will be added in a future version as we continue to expand tracing coverage.
Even with these exceptions, GLIDE 2.0 provides comprehensive insights across the vast majority of standard operations, making it easy to adopt observability best practices with minimal effort.
To begin collecting telemetry data with GLIDE 2.0:
- Set up an OpenTelemetry Collector to receive trace and metric data.
 - Configure the GLIDE client with the endpoint to your collector.
 - Alternatively, you can configure GLIDE to export telemetry data directly to a local file for development or debugging purposes, without requiring a running collector.
 
GLIDE does not export data directly to third-party services—instead, it sends data to your collector, which routes it to your backend (e.g., CloudWatch, Prometheus, Jaeger).
You can configure the OTel collector endpoint using one of the following protocols:
- 
http://orhttps://- Send data via HTTP(S) - 
grpc://- Use gRPC for efficient telemetry transmission - 
file://- Write telemetry data to a local file (ideal for local dev/debugging) 
When initializing OpenTelemetry, you can customize behavior using the openTelemetryConfig object.
Note: Both traces and metrics are optional—but at least one must be provided in the openTelemetryConfig. If neither is set, OpenTelemetry will not emit any data.
openTelemetryConfig.traces- endpoint (required): The trace collector endpoint.
 - 
samplePercentage (optional): Percentage (0–100) of commands to sample for tracing. Default: 
1.- For production, a low sampling rate (1–5%) is recommended to balance performance and insight.
 
 
openTelemetryConfig.metrics- endpoint (required): The metrics collector endpoint.
 
openTelemetryConfig.flushIntervalMs- (optional): Time in milliseconds between flushes to the collector. Default: 
5000. 
If using file:// as the endpoint:
- The path must begin with 
file://. - If a directory is provided (or no file extension), data is written to 
signals.jsonin that directory. - If a filename is included, it will be used as-is.
 - The parent directory must already exist.
 - Data is appended, not overwritten.
 
- 
flushIntervalMsmust be a positive integer. - 
samplePercentagemust be between 0 and 100. - File exporter paths must start with 
file://and have an existing parent directory. - Invalid configuration will throw an error synchronously when calling 
OpenTelemetry.init(). 
OpenTelemetry.init() can only be called once per process. Subsequent calls will be ignored. To change configuration, restart the process.
import { OpenTelemetry, OpenTelemetryConfig, OpenTelemetryTracesConfig, OpenTelemetryMetricsConfig } from "@valkey/valkey-glide";
// Define traces configuration
const tracesConfig: OpenTelemetryTracesConfig = {
  endpoint: "http://localhost:4318/v1/traces",
  samplePercentage: 10  // Optional, defaults to 1%
};
// Define metrics configuration
const metricsConfig: OpenTelemetryMetricsConfig = {
  endpoint: "http://localhost:4318/v1/metrics"
};
// Complete OpenTelemetry configuration
const openTelemetryConfig: OpenTelemetryConfig = { 
  traces: tracesConfig,           // Optional: can omit if only metrics are needed
  metrics: metricsConfig,         // Optional: can omit if only traces are needed
  flushIntervalMs: 1000           // Optional, defaults to 5000 ms
};
// Initialize OpenTelemetry (can only be called once per process)
OpenTelemetry.init(openTelemetryConfig);✅ In this example, both traces and metrics are configured, but you can configure only one of them if you wish. At least one must be provided.
By default, when connecting to Valkey, Valkey GLIDEs operates in an unauthenticated mode.
Valkey GLIDE also offers support for an authenticated connection mode.
In authenticated mode, you have the following options:
- Use both a username and password, which is recommended and configured through ACLs on the server.
 - Use a password only, which is applicable if the server is configured with the requirepass setting.
 
To provide the necessary authentication credentials to the client, you can use the ServerCredentials class.
See the General Concepts section for a detailed explanation about using ACLs with GLIDE.
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const credentials = {
    username: "user1",
    password: "passwordA"
};
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    credentials: credentials
});import {GlideClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const credentials = {
    username: "user1",
    password: "passwordA"
};
const client = await GlideClient.createClient({
    addresses: addresses,
    credentials: credentials
});See the General Concepts section for a detailed explanation about using IAM authentication with GLIDE.
The example below utilizes the AWS SDK for the IAM token generation. Please refer to the AWS SDK docs for a detailed explanation regarding generating the IAM token.
Token generation-
import { SignatureV4 } from "@smithy/signature-v4";
import { HttpRequest } from "@smithy/protocol-http";
import { defaultProvider } from "@aws-sdk/credential-provider-node";
import { formatUrl } from "@aws-sdk/util-format-url";
import { Sha256 } from "@aws-crypto/sha256-js";
class ElastiCacheIAMProvider {
    private user: string;
    private clusterName: string;
    private region: string;
    constructor(user: string, clusterName: string, region: string = "us-east-1") {
        this.user = user;
        this.clusterName = clusterName;
        this.region = region;
    }
    async  getCredentials() {
        const credentials = await defaultProvider()();
    
        const signer = new SignatureV4({
            service: "elasticache",
            credentials,
            region: this.region,
            sha256: Sha256,
        });
    
        const url = new URL(`https://${this.clusterName}/`);
        url.searchParams.append("Action", "connect");
        url.searchParams.append("User", this.user);
    
        const request = new HttpRequest({
            protocol: url.protocol,
            hostname: url.hostname,
            method: "GET",
            path: url.pathname,
            query: Object.fromEntries(url.searchParams),
            headers: {
                host: url.hostname,
            },
        });
    
        const signedRequest = await signer.presign(request, { expiresIn: 900 });
        return formatUrl(signedRequest).replace(/^https?:\/\//, "");
    }
}Usage example -
import { GlideClusterClient, GlideClusterClientConfiguration, ServerCredentials, AdvancedGlideClusterClientConfiguration } from "@valkey/valkey-glide";
async function main() {
    const username = "your-username";
    const cluster_name = "your-cluster-name";
    const endpoint = "example-cluster-endpoint.use1.cache.amazonaws.com";
    const addresses = [
        {
            host: endpoint,
            port: 6379,
        },
    ];
    const provider = new ElastiCacheIAMProvider(
        username,
        cluster_name,
        "us-east-1"
    );
    const iamAuthToken = await provider.getCredentials();
    const credentials: ServerCredentials = {
        username: username,
        password: iamAuthToken
    };
    const config: GlideClusterClientConfiguration = {
        addresses: addresses,
        credentials: credentials,
        useTLS: true,
        clientName: 'my-client',
    };
    
    const client = await GlideClusterClient.createClient(config);
    
    // Update password dynamically
    const newIAMAuthToken = await provider.getCredentials();
    await client.updateConnectionPassword(newIAMAuthToken);
    
    // To perform immediate re-authentication, set the second parameter to true
    await client.updateConnectionPassword(newIAMAuthToken, true);
}Valkey GLIDE supports secure TLS connections to a data store.
It's important to note that TLS support in Valkey GLIDE relies on rustls. Currently, Valkey GLIDE employs the default rustls settings with no option for customization.
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    useTLS: true
});import {GlideClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClient.createClient({
    addresses: addresses,
    useTLS: true
});The tlsAdvancedConfiguration option provides advanced TLS settings for both standalone and cluster clients.
Insecure TLS mode bypasses certificate verification. This is useful when connecting to servers using self-signed certificates or when DNS entries don't match certificate hostnames.
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    useTLS: true,
    advancedConfiguration: {
        tlsAdvancedConfiguration: {
            insecure: true
        }
    }
});You can provide custom root certificates for TLS connections. This is useful when connecting to servers with self-signed certificates or corporate certificate authorities.
Certificate Behavior:
- If 
rootCertificatesis not provided (undefined), the system's default certificate trust store is used - If 
rootCertificatesis an empty Buffer or string, an error will be returned - Certificates must be in PEM format
 - Can be provided as a 
stringorBuffer - Multiple certificates can be provided by concatenating them in PEM format
 
import {GlideClusterClient} from "@valkey/valkey-glide";
import * as fs from "fs";
// Read certificate file
const rootCert = fs.readFileSync("/path/to/ca-cert.pem");
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    useTLS: true,
    advancedConfiguration: {
        tlsAdvancedConfiguration: {
            rootCertificates: rootCert
        }
    }
});import {GlideClient} from "@valkey/valkey-glide";
const certString = `-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKmzMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
...
-----END CERTIFICATE-----`;
const addresses = [
    {
        host: "primary.example.com",
        port: 6379
    }
];
const client = await GlideClient.createClient({
    addresses: addresses,
    useTLS: true,
    advancedConfiguration: {
        tlsAdvancedConfiguration: {
            rootCertificates: certString
        }
    }
});import {GlideClusterClient} from "@valkey/valkey-glide";
import * as fs from "fs";
// Read multiple certificate files
const cert1 = fs.readFileSync("/path/to/cert1.pem");
const cert2 = fs.readFileSync("/path/to/cert2.pem");
const cert3 = fs.readFileSync("/path/to/cert3.pem");
// Concatenate certificates
const combinedCerts = Buffer.concat([cert1, cert2, cert3]);
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    useTLS: true,
    advancedConfiguration: {
        tlsAdvancedConfiguration: {
            rootCertificates: combinedCerts
        }
    }
});import {GlideClient} from "@valkey/valkey-glide";
import * as fs from "fs";
const rootCert = fs.readFileSync("/path/to/ca-cert.pem");
const addresses = [
    {
        host: "primary.example.com",
        port: 6379
    }
];
const client = await GlideClient.createClient({
    addresses: addresses,
    useTLS: true,
    advancedConfiguration: {
        tlsAdvancedConfiguration: {
            insecure: true,
            rootCertificates: rootCert
        }
    }
});All certificates must be in PEM format. A PEM certificate looks like this:
-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJAKL0UG+mRKmzMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
...
-----END CERTIFICATE-----
Common Issues:
- 
Certificate Verification Failed
- Ensure the certificate is valid and not expired
 - Verify the hostname matches the certificate's Common Name (CN) or Subject Alternative Name (SAN)
 - Check that the certificate chain is complete
 
 - 
Connection Refused
- Verify the server is configured to accept TLS connections
 - Ensure the port number is correct (typically 6379 for TLS)
 
 - 
Empty Certificate Error
- Do not provide an empty Buffer or string for 
rootCertificates - Either provide valid certificates or leave it undefined to use system certificates
 
 - Do not provide an empty Buffer or string for 
 - 
File Not Found
- Verify the certificate file path is correct
 - Ensure the file is accessible with proper permissions
 
 
By default, Valkey GLIDE directs read commands to the primary node that owns a specific slot. For applications that prioritize read throughput and can tolerate possibly stale data, Valkey GLIDE provides the flexibility to route reads to replica nodes.
Valkey GLIDE provides support for next read strategies, allowing you to choose the one that best fits your specific use case.
| Strategy | Description | 
|---|---|
primary | 
Always read from primary, in order to get the freshest data | 
preferReplica | 
Spread requests between all replicas in a round robin manner. If no replica is available, route the requests to the primary | 
AZAffinity | 
Spread the read requests between replicas in the same client's availability zone in a round robin manner, falling back to other replicas or the primary if needed. | 
AZAffinityReplicasAndPrimary | 
Spread the read requests among nodes within the client's availability zone in a round robin manner, prioritizing local replicas, then the local primary, and falling back to other replicas or the primary if needed. | 
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    readFrom: "preferReplica"
});
await client.set("key1", "val1");
/// get will read from one of the replicas
await client.get("key1");If ReadFrom strategy is AZAffinity, 'clientAz' setting is required to ensures that readonly commands are directed to replicas within the specified AZ if exits.
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    readFrom: "AZAffinity" as ReadFrom,
    clientAz: "us-east-1a",
});
await client.set("key1", "val1");
/// get will read from one of the replicas in the same client's availability zone if exits.
await client.get("key1");If ReadFrom strategy is AZAffinityReplicasAndPrimary, 'clientAz' setting is required to ensures that readonly commands are directed to replicas or primary within the specified AZ if exits.
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    readFrom: "AZAffinityReplicasAndPrimary" as ReadFrom,
    clientAz: "us-east-1a",
});
await client.set("key1", "val1");
/// get will read from one of the replicas or the primary in the same client's availability zone if exits.
await client.get("key1");Valkey GLIDE allows you to configure timeout settings and reconnect strategies. These configurations can be applied through the GlideClusterClientConfiguration and GlideClientConfiguration parameters.
| Configuration setting | Description | Default value | 
|---|---|---|
| requestTimeout | This specified time duration, measured in milliseconds, represents the period during which the client will await the completion of a request. This time frame includes the process of sending the request, waiting for a response from the node(s), and any necessary reconnection or retry attempts. If a pending request exceeds the specified timeout, it will trigger a timeout error. If no timeout value is explicitly set, a default value will be employed. | 250 milliseconds | 
| connectionBackoff | The reconnection strategy defines how and when reconnection attempts are made in the event of connection failures | Exponential backoff | 
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    requestTimeout: 500
});A transaction in Valkey Glide allows you to execute a group of commands in a single, atomic step. This ensures that all commands in the transaction are executed sequentially and without interruption. See Valkey Transactions.
This is equivalent to the Valkey commands MULTI / EXEC.
There are two primary modes for handling transactions in Glide:
- 
Standalone Mode: Use the 
Transactionclass. - 
Cluster Mode: Use the 
ClusterTransactionclass. 
Transaction objects can be reused. If you need to execute a particular group of commands multiple times, you can simply resend the same transaction object.
Here's a simple example demonstrating how to create and execute a transaction in standalone mode:
import {Transaction} from "@valkey/valkey-glide";
// Initialize a transaction object
const transaction = new Transaction();
// Add commands to the transaction
transaction.set('key', 'value');
transaction.select(1);  // Standalone command
transaction.get('key');
// Execute the transaction
const result = await client.exec(transaction);
console.log(result); // Output: [OK, OK, null]Valkey Glide supports command chaining within a transaction, allowing for a more concise and readable code. Here's how you can use chaining in transactions:
import {ClusterTransaction} from "@valkey/valkey-glide";
// Initialize a cluster transaction object
const clusterTransaction = new ClusterTransaction();
// Chain commands
clusterTransaction.set('key', 'value').get('key')
// Execute the transaction
const result = await client.exec(clusterTransaction);
console.log(result); // Output: [OK, 'value']Cluster Mode Considerations: When using ClusterTransaction, all keys in the transaction must be mapped to the same slot.
Creating a Transaction: Initialize the Transaction or ClusterTransaction object.
import {Transaction, ClusterTransaction}  from "@valkey/valkey-glide";
const transaction = new Transaction();  // For standalone mode
const clusterTransaction = new ClusterTransaction();  // For cluster modeAdding Commands: Use the transaction object to queue up the desired commands.
transaction.set('key', 'value');
transaction.get('key');Executing the Transaction: Use the exec method of the Valkey Glide client to execute the transaction.
await client.exec(transaction);Handling Results: The result of the transaction execution will be a list of responses corresponding to each command in the transaction.
const result = await client.exec(transaction)
console.log(result);  // Output: [OK, 'value']GLIDE 1.2 introduces a new NONE Valkey API: getStatistics which returns an Object with (currently) 2 properties (available for both GlideClient & GlideClusterClient):
- 
total_connectionscontains the number of active connections across all clients - 
total_clientscontains the number of active clients (regardless of its type) 
import {GlideClusterClient} from "@valkey/valkey-glide";
const addresses = [
    {
        host: "address.example.com",
        port: 6379
    }
];
const client = await GlideClusterClient.createClient({
    addresses: addresses,
    requestTimeout: 500
});
// Retrieve statistics
const stats = await client.getStatistics();
// Example: Accessing and printing statistics
console.log(`Total Connections: ${stats.total_connections}`);
console.log(`Total Clients: ${stats.total_clients}`);