title: Connect with Redis client API libraries

summary: Connect your application to a Redis database and try an example

summary: Connect your Python application to a Redis database

title: redis-py guide (Python)

summary: Connect your Python vector application to a Redis vector database

title: Redis vector library guide (Python)

summary: Connect your .NET application to a Redis database

title: NRedisStack guide (C#/.NET)

summary: Connect your Node.js/JavaScript application to a Redis database

title: node-redis guide (JavaScript)

title: ioredis guide (JavaScript)

summary: Connect your Java application to a Redis database

title: Jedis guide (Java)

summary: Connect your Lettuce application to a Redis database

title: Lettuce guide (Java)

summary: Connect your Go application to a Redis database

title: go-redis guide (Go)

summary: Connect your PHP application to a Redis database

title: Predis guide (PHP)

summary: Connect your Rust application to a Redis database

title: redis-rs guide (Rust)

title: hiredis guide (C)

summary: Connect your Ruby application to a Redis database

title: redis-rb guide (Ruby)

summary: Object-Mapper libraries for Redis Open Source

title: Object-Mapper libraries

summary: Server-assisted, client-side caching in Redis

title: Client-side caching introduction

summary: Manage Redis connections efficiently

title: Connection pools and multiplexing

summary: Learn how to handle errors when using Redis client libraries.

title: Error handling

summary: Improve reliability using the failover/failback features of client libraries.

title: Client-side geographic failover

summary: Learn how to avoid disruptions during Redis server maintenance.

title: Smart client handoffs

summary: Monitor your client's activity for optimization and debugging.

title: Observability

summary: Novel patterns for working with Redis data structures

title: Coding patterns

title: Overview

text:
Use the Redis client libraries to connect to Redis servers from
your own code. We document the following client libraries
for eight main languages:

| Language | Client name | Docs | Supported |
| :-- | :-- | :-- | :-- |
| [Python](https://www.python.org/) | [`redis-py`](https://github.com/redis/redis-py) |[`redis-py` guide]() | Yes |
| [Python](https://www.python.org/) | [`RedisVL`](https://github.com/redis/redis-vl-python) |[RedisVL guide]() | Yes
| [C#/.NET](https://learn.microsoft.com/en-us/dotnet/csharp/) | [`NRedisStack`](https://github.com/redis/NRedisStack) |[`NRedisStack` guide]() | Yes |
| [JavaScript](https://nodejs.org/en) | [`node-redis`](https://github.com/redis/node-redis) | [`node-redis` guide]() | Yes |
| [JavaScript](https://nodejs.org/en) | [`ioredis`](https://github.com/redis/ioredis) | [`ioredis` guide]() | Yes |
| [Java](https://www.java.com/en/) | [`Jedis`](https://github.com/redis/jedis) | [`Jedis` guide]() |  Yes |
| [Java](https://www.java.com/en/) | [`Lettuce`](https://github.com/redis/lettuce) | [`Lettuce` guide]() | Yes |
| [Go](https://go.dev/) | [`go-redis`](https://github.com/redis/go-redis) | [`go-redis` guide]() | Yes |
| [PHP](https://www.php.net/)| [`Predis`](https://github.com/predis/predis) | [`Predis` guide]() | Best effort [*](#best-effort) |
| [C](https://en.wikipedia.org/wiki/C_(programming_language)) | [`hiredis`](https://github.com/redis/hiredis) | [`hiredis` guide]() | Yes |
| [Rust](https://www.rust-lang.org/) | [`redis-rs`](https://github.com/redis-rs/redis-rs) | [`redis-rs` guide]() | Best effort [*](#best-effort) |
| [Ruby](https://www.ruby-lang.org/en/) | [`redis-rb`](https://github.com/redis/redis-rb) | [`redis-rb` guide]() | Yes |

*
Redis does not provide official support for third-party client libraries.
However, we contribute new features, offer guidance, and collaborate with the community
on a best-effort basis to help ensure these libraries remain reliable and up-to-date.

We also provide several higher-level
[object mapping (OM)]()
libraries for [Python](),
[C#/.NET](),
[Node.js](), and
[Java/Spring]().

title: Community-supported clients

text:
The table below shows the recommended third-party client libraries for languages that
Redis does not document directly:

| Language | Client name | Github | Docs |
| :-- | :-- | :-- | :-- |
| [C++](https://en.wikipedia.org/wiki/C%2B%2B) | Boost.Redis | https://github.com/boostorg/redis | https://www.boost.org/doc/libs/develop/libs/redis/doc/html/index.html |
| [Dart](https://dart.dev/) | redis_dart_link | https://github.com/toolsetlink/redis_dart_link | https://github.com/toolsetlink/redis_dart_link |
| [PHP](https://www.php.net/) | PhpRedis extension | https://github.com/phpredis/phpredis | https://github.com/phpredis/phpredis/blob/develop/README.md |

title: Requirements

text:
You will need access to a Redis server to use these libraries.
You can experiment with a local installation of Redis Open Source
(see [Install Redis Open Source]()) or with a free trial of [Redis Cloud]().
To interact with a Redis server without writing code, use the
[Redis CLI]() and
[Redis Insight]() tools.

title: Choose a client library for your language

text:
For some languages, we only recommend one client library, but Python, JavaScript,
Java, C#, and PHP have multiple options. The sections below summarize the differences
between the options for each language.

title: Python

text:
-   [`redis-py`](https://github.com/redis/redis-py) is the recommended Python client library for
    most use cases.
-   [`RedisVL`](https://github.com/redis/redis-vl-python) is specialized for handling
    high-dimensional vector data and is a good choice for AI/ML workflows.
-   [RedisOM for Python](https://github.com/redis/redis-om-python) is an object mapping library that
    provides a high-level API for working with Redis data structures.

title: JavaScript

text:
-   [`node-redis`](https://github.com/redis/node-redis) is the recommended JavaScript client library
    for most use cases.
-   [`ioredis`](https://github.com/redis/ioredis) is an older library that is still supported, but
    lacks some of the newer features and performance optimizations of `node-redis`.
    Note that there is a migration guide available if you are interested in converting
    your `ioredis` project to `node-redis`
    (see [Migrate from ioredis]()).
-   [RedisOM for Node.js](https://github.com/redis/redis-om-node) is an object mapping library that
    provides a high-level API for working with Redis data structures.

title: Java

text:
-   [`Jedis`](https://github.com/redis/jedis) supports the full feature set of Redis and has a
    straightforward API, but is limited to synchronous operations.
-   [`Lettuce`](https://github.com/redis/lettuce) supports synchronous, asynchronous,
    and reactive operations. However, it has a more complex API than Jedis and doesn't currently
    support all Redis features (notably time series and probabilistic data structures).
-   [RedisOM for Java](https://github.com/redis/redis-om-java) is an object mapping library that
    provides a high-level API for working with Redis data structures.

title: C#

text:
-   [`NRedisStack`](https://github.com/redis/NRedisStack) is the recommended C# client
    library for most use cases.
-   [RedisOM for .NET](https://github.com/redis/redis-om-dotnet) is an object mapping library that
    provides a high-level API for working with Redis data structures.

title: PHP

text:
-   [`Predis`](https://github.com/predis/predis) is the recommended PHP client library for
    most use cases. It has "best effort" support from the Redis team (it's a third-party library
    but the Redis team contributes to it and helps with issues) and has good coverage in the
    [Redis documentation](). However, it is implemented in
    PHP, which limits its performance compared to [phpredis](https://github.com/phpredis/phpredis),
    which is implemented in C.
-   [phpredis](https://github.com/phpredis/phpredis) is a popular and well-maintained PHP client
    library that is implemented using C extensions to PHP for better performance. However, it is
    not actively supported or documented by the Redis team.

title: Client library decision tree

text:
Use the decision tree below to help you choose the right client library for your needs,
based on the recommendations in the previous sections. Note that you should regard the
conclusions as a guideline for your research, not as a definitive answer.

[code example]

code:
id: client-recommendation
scope: clients
indentWidth: 28
rootQuestion: singleClientLanguageQuestion
questions:
    singleClientLanguageQuestion:
        text: |
            Are you using Go, Rust, C, C++, Dart, or Ruby?
        whyAsk: |
            These languages have only one recommended client library,
            so the choice is straightforward
        answers:
            yes:
                value: "Yes"
                outcome:
                    label: |
                        These languages only have one recommended client library. Use
                        the client library for your language listed in the table above.
                    id: singleClientLanguageOutcome
            no:
                value: "No"
                nextQuestion: multiClientLanguageQuestion

    multiClientLanguageQuestion:
        text: |
            Are you using Python, JavaScript, Java, or C#/.NET
            and require object mapping (ORM-like) functionality?
        whyAsk: |
            RedisOM provides a high-level API for these languages.
            If you don't need OM, we'll help you choose the best low-level client
        answers:
            yes:
                value: "Yes"
                outcome:
                    label: |
                        Use RedisOM for your language
                        (available for Python, JavaScript, Java, and C#/.NET)
                    id: redisOMOutcome
            no:
                value: "No"
                nextQuestion: lowLevelClientQuestion

    lowLevelClientQuestion:
        text: Which language are you using?
        whyAsk: |
            Different languages have different low-level client libraries
            optimized for their ecosystems
        answers:
            python:
                value: Py
                nextQuestion: pythonLowLevelQuestion
            javascript:
                value: JS
                nextQuestion: javascriptLowLevelQuestion
            java:
                value: Java
                nextQuestion: javaLowLevelQuestion
            php:
                value: PHP
                nextQuestion: phpLowLevelQuestion
            dotnet:
                value: "C#"
                outcome:
                    label: Use NRedisStack
                    id: nredisStackOutcome

    pythonLowLevelQuestion:
        text: |
            Are you building an AI/ML application
            mainly based around high-dimensional vector operations?
        whyAsk: |
            RedisVL is specialized for AI/ML workflows with vector data,
            while redis-py is better for general-purpose use
        answers:
            yes:
                value: "Yes"
                outcome:
                    label: Use RedisVL
                    id: redisVLOutcome
            No:
                value: "No"
                outcome:
                    label: Use redis-py
                    id: redisPyOutcome

    javaLowLevelQuestion:
        text: Do you need async or reactive operations?
        whyAsk: |
            Jedis supports only synchronous operations with a simpler API,
            while Lettuce supports async and reactive patterns
        answers:
            yes:
                value: "Yes"
                outcome:
                    label: Use Lettuce
                    id: lettuceOutcome
            no:
                value: "No"
                outcome:
                    label: Use Jedis
                    id: jedisOutcome

    javascriptLowLevelQuestion:
        text: Do you have an existing codebase using ioredis?
        whyAsk: |
            If you're already using ioredis, you can continue with it.
            For new projects, node-redis is the recommended choice
        answers:
            yes:
                value: "Yes"
                nextQuestion: ioredisAdvancedFeaturesQuestion
            no:
                value: "No"
                outcome:
                    label: Use node-redis
                    id: nodeRedisOutcome

    ioredisAdvancedFeaturesQuestion:
        text: Do you want to use advanced Redis features such as search, vector database, and JSON?
        answers:
            yes:
                value: "Yes"
                outcome:
                    label: Migrate to node-redis using our migration guide
                    id: migrateToNodeRedisOutcome
            no:
                value: "No"
                outcome:
                    label: Continue using ioredis
                    id: continueIoredisOutcome

    phpLowLevelQuestion:
        text: |
            Is maximum performance a higher priority than full support and documentation?
        whyAsk: |
            PhpRedis is a C extension with better performance,
            while Predis is a pure PHP implementation that is better supported and documented
        answers:
            yes:
                value: "Yes"
                outcome:
                    label: Use PhpRedis
                    id: phpredisOutcome
            no:
                value: "No"
                outcome:
                    label: Use Predis
                    id: predisOutcome

section_id: client-library-decision-tree


title: Connect to the server

summary: Connect your Python application to a Redis database

page_type: content

title: Basic connection

role: overview

text:
Connect to localhost on port 6379:

[code example]

You can also specify a full set of connection options:

[code example]

Store and retrieve a simple string.

[code example]

title: Connect to a Redis cluster

role: content

text:
To connect to a Redis cluster, use `Redis.Cluster()`, passing an array of
endpoints.

[code example]

title: Connect to your production Redis with TLS

text:
When you deploy your application, use TLS and follow the [Redis security]() guidelines.

[code example]

code: const redis = new Redis();

section_id: basic-connection

code:
const redis = new Redis({
  port: 6379,
  host: "127.0.0.1",
  username: "default",
  password: "my-password",
  db: 0,
});

code:
await redis.set('foo', 'bar');
const value = await redis.get('foo');
console.log(value); // >>> bar

code:
const redis = new Redis.Cluster([
    {
        host: '127.0.0.1',
        port: 6380,
        password: 'my-password',
        username: 'default',
    },
    {
        host: '127.0.0.1',
        port: 6381,
        password: 'my-other-password',
        username: 'default',
    },
    // ...
]);

section_id: connect-to-a-redis-cluster

code:
const redis = new Redis({
  host: "localhost",
  //...
  tls: {
    key: readFileSync('./redis_user_private.key'),
    cert: readFileSync('./redis_user.crt'),
    ca: fs.readFileSync('./redis_ca.pem'),
  },
});


title: ioredis guide (JavaScript)

title: Connect to the server

title: Install

role: setup

text:
To install `ioredis`, run:

[code example]

title: Connect and test

text:
Connect to localhost on port 6379.

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

Store and retrieve a simple string.

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

Store and retrieve a map.

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

When you have finished using a connection, close it with `client.quit()`.

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

title: More information

text:
The [Github repository](https://github.com/redis/ioredis) has useful
information, including [API docs](https://redis.github.io/ioredis/index.html)
and a set of [code examples](https://github.com/redis/ioredis/tree/main/examples).

code: npm install ioredis

section_id: install

code:
#include <stdio.h>
#include <stdlib.h>

#include <hiredis/hiredis.h>

int main() {
    // The `redisContext` type represents the connection
    // to the Redis server. Here, we connect to the
    // default host and port.
    redisContext *c = redisConnect("127.0.0.1", 6379);

    // Check if the context is null or if a specific
    // error occurred.
    if (c == NULL || c->err) {
        if (c != NULL) {
            printf("Error: %s\n", c->errstr);
            // handle error
        } else {
            printf("Can't allocate redis context\n");
        }

        exit(1);
    }

    // Set a string key.
    redisReply *reply = redisCommand(c, "SET foo bar");
    printf("Reply: %s\n", reply->str); // >>> Reply: OK
    freeReplyObject(reply);

    // Get the key we have just stored.
    reply = redisCommand(c, "GET foo");
    printf("Reply: %s\n", reply->str); // >>> Reply: bar
    freeReplyObject(reply);

    // Close the connection.
    redisFree(c);
}

section_id: connect-and-test

code:
rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password
		DB:       0,  // use default DB
		Protocol: 2,
	})

	ctx := context.Background()

code: RedisClient jedis = new RedisClient("redis://localhost:6379");

code:
import { createClient } from 'redis';

const client = createClient();

client.on('error', err => console.log('Redis Client Error', err));

await client.connect();

code:
import { Redis } from 'ioredis';

const redis = new Redis();

code: r = Redis.new

code:
err := rdb.Set(ctx, "foo", "bar", 0).Err()
	if err != nil {
		panic(err)
	}

	val, err := rdb.Get(ctx, "foo").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("foo", val) // >>> foo bar

code:
String res1 = jedis.set("bike:1", "Deimos");
        System.out.println(res1); // >>> OK

        String res2 = jedis.get("bike:1");
        System.out.println(res2); // >>> Deimos

code:
await client.set('key', 'value');
const value = await client.get('key');
console.log(value); // >>> value

code:
await redis.set('key', 'value');
const value = await redis.get('key');
console.log(value); // >>> value

code:
hashFields := []string{
		"model", "Deimos",
		"brand", "Ergonom",
		"type", "Enduro bikes",
		"price", "4972",
	}

	res1, err := rdb.HSet(ctx, "bike:1", hashFields).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res1) // >>> 4

	res2, err := rdb.HGet(ctx, "bike:1", "model").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res2) // >>> Deimos

	res3, err := rdb.HGet(ctx, "bike:1", "price").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res3) // >>> 4972

	res4, err := rdb.HGetAll(ctx, "bike:1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res4)
	// >>> map[brand:Ergonom model:Deimos price:4972 type:Enduro bikes]

code:
import io.lettuce.core.*;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

public class ConnectBasicTest {

    public void connectBasic() {
        RedisURI uri = RedisURI.Builder
                .redis("localhost", 6379)
                .build();

        RedisClient client = RedisClient.create(uri);
        StatefulRedisConnection<String, String> connection = client.connect();
        RedisCommands<String, String> commands = connection.sync();

        commands.set("foo", "bar");
        String result = commands.get("foo");
        System.out.println(result); // >>> bar

        connection.close();
        client.shutdown();
    }
}

code:
Map<String, String> hash = new HashMap<>();
        hash.put("name", "John");
        hash.put("surname", "Smith");
        hash.put("company", "Redis");
        hash.put("age", "29");

        Long res3 = jedis.hset("user-session:123", hash);
        System.out.println(res3); // >>> 4

        Map<String, String> res4 = jedis.hgetAll("user-session:123");
        System.out.println(res4);
        // >>> {name=John, surname=Smith, company=Redis, age=29}

code:
await client.hSet('user-session:123', {
    name: 'John',
    surname: 'Smith',
    company: 'Redis',
    age: 29
})

let userSession = await client.hGetAll('user-session:123');
console.log(JSON.stringify(userSession, null, 2));
/* >>>
{
  "surname": "Smith",
  "name": "John",
  "company": "Redis",
  "age": "29"
}
 */

code:
await redis.hset('user-session:123', {
    name: 'John',
    surname: 'Smith',
    company: 'Redis',
    age: 29
});

const userSession = await redis.hgetall('user-session:123');
console.log(JSON.stringify(userSession, null, 2));
/* >>>
{
  "surname": "Smith",
  "name": "John",
  "company": "Redis",
  "age": "29"
}
 */

code:
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)

r.set('foo', 'bar')
# True
r.get('foo')
# bar

r.hset('user-session:123', mapping={
    'name': 'John',
    "surname": 'Smith',
    "company": 'Redis',
    "age": 29
})
# True

r.hgetall('user-session:123')
# {'surname': 'Smith', 'name': 'John', 'company': 'Redis', 'age': '29'}

r.close()

code:
require 'redis'

r = Redis.new

r.set 'foo', 'bar'
value = r.get('foo')
puts value # >>> bar

r.hset 'user-session:123', 'name', 'John'
r.hset 'user-session:123', 'surname', 'Smith'
r.hset 'user-session:123', 'company', 'Redis'
r.hset 'user-session:123', 'age', 29

hash_value = r.hgetall('user-session:123')
puts hash_value
# >>> {"name"=>"John", "surname"=>"Smith", "company"=>"Redis", "age"=>"29"}

r.close()

code:
using NRedisStack;
using NRedisStack.RedisStackCommands;
using StackExchange.Redis;

public class AsyncLandingExample
{
    public async Task Run()
    {
        var muxer = await ConnectionMultiplexer.ConnectAsync("localhost:6379");
        var db = muxer.GetDatabase();

        await db.StringSetAsync("foo", "bar");
        string? fooResult = await db.StringGetAsync("foo");
        Console.WriteLine(fooResult); // >>> bar

        var hash = new HashEntry[] {
            new HashEntry("name", "John"),
            new HashEntry("surname", "Smith"),
            new HashEntry("company", "Redis"),
            new HashEntry("age", "29"),
            };
        await db.HashSetAsync("user-session:123", hash);

        var hashFields = await db.HashGetAllAsync("user-session:123");
        Console.WriteLine(String.Join("; ", hashFields));
        // >>> name: John; surname: Smith; company: Redis; age: 29
    }
}

code:
using NRedisStack;
using NRedisStack.RedisStackCommands;
using StackExchange.Redis;

public class SyncLandingExample
{
    public void Run()
    {
        var muxer = ConnectionMultiplexer.Connect("localhost:6379");
        var db = muxer.GetDatabase();

        db.StringSet("foo", "bar");
        Console.WriteLine(db.StringGet("foo")); // >>> bar

        var hash = new HashEntry[] {
            new HashEntry("name", "John"),
            new HashEntry("surname", "Smith"),
            new HashEntry("company", "Redis"),
            new HashEntry("age", "29"),
        };
        db.HashSet("user-session:123", hash);

        var hashFields = db.HashGetAll("user-session:123");
        Console.WriteLine(String.Join("; ", hashFields));
        // >>> name: John; surname: Smith; company: Redis; age: 29
    }
}

code:
connection.close();
        client.shutdown();

code: await client.quit();

code:
<?php

require 'vendor/autoload.php';

use Predis\Client as PredisClient;

$r = new PredisClient([
                'scheme'   => 'tcp',
                'host'     => '127.0.0.1',
                'port'     => 6379,
                'password' => '',
                'database' => 0,
            ]);

echo $r->set('foo', 'bar'), PHP_EOL;
// >>> OK

echo $r->get('foo'), PHP_EOL;
// >>> bar

$r->hset('user-session:123', 'name', 'John');
$r->hset('user-session:123', 'surname', 'Smith');
$r->hset('user-session:123', 'company', 'Redis');
$r->hset('user-session:123', 'age', 29);

echo var_export($r->hgetall('user-session:123')), PHP_EOL;
/* >>>
array (
  'name' => 'John',
  'surname' => 'Smith',
  'company' => 'Redis',
  'age' => '29',
)
*/

code:
mod tests {
    use redis::AsyncCommands;

    async fn run() {
        let mut r = match redis::Client::open("redis://127.0.0.1") {
            Ok(client) => {
                match client.get_multiplexed_async_connection().await {
                    Ok(conn) => conn,
                    Err(e) => {
                        println!("Failed to connect to Redis: {e}");
                        return;
                    }
                }
            },
            Err(e) => {
                println!("Failed to create Redis client: {e}");
                return;
            }
        };

        if let Ok(res) = r.set("foo", "bar").await {
            let res: String = res;
            println!("{res}"); // >>> OK
        } else {
            println!("Error setting foo");
        }

        match r.get("foo").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> bar
            },
            Err(e) => {
                println!("Error getting foo: {e}");
                return;
            }
        };

        let hash_fields = [
            ("model", "Deimos"),
            ("brand", "Ergonom"),
            ("type", "Enduro bikes"),
            ("price", "4972"),
        ];

        if let Ok(res) = r.hset_multiple("bike:1", &hash_fields).await {
            let res: String = res;
            println!("{res}"); // >>> OK
        } else {
            println!("Error setting bike:1");
        }

        match r.hget("bike:1", "model").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> Deimos
            },
            Err(e) => {
                println!("Error getting bike:1 model: {e}");
                return;
            }
        }

        match r.hget("bike:1", "price").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> 4972
            },
            Err(e) => {
                println!("Error getting bike:1 price: {e}");
                return;
            }
        }

        match r.hgetall("bike:1").await {
            Ok(res) => {
                let res: Vec<(String, String)> = res;

                for (key, value) in res {
                    println!("{key}: {value}");
                }
                // >>> model: Deimos
                // >>> brand: Ergonom
                // >>> type: Enduro bikes
                // >>> price: 4972
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        }
    }
}

code:
mod landing_tests {
    use redis::Commands;

    fn run() {
        let mut r = match redis::Client::open("redis://127.0.0.1") {
            Ok(client) => {
                match client.get_connection() {
                    Ok(conn) => conn,
                    Err(e) => {
                        println!("Failed to connect to Redis: {e}");
                        return;
                    }
                }
            },
            Err(e) => {
                println!("Failed to create Redis client: {e}");
                return;
            }
        };

        if let Ok(res) = r.set("foo", "bar") {
            let res: String = res;
            println!("{res}");    // >>> OK
        } else {
            println!("Error setting foo");
        }

        match r.get("foo") {
            Ok(res) => {
                let res: String = res;
                println!("{res}");   // >>> bar
            },
            Err(e) => {
                println!("Error getting foo: {e}");
                return;
            }
        };

        let hash_fields = [
            ("model", "Deimos"),
            ("brand", "Ergonom"),
            ("type", "Enduro bikes"),
            ("price", "4972"),
        ];

        if let Ok(res) = r.hset_multiple("bike:1", &hash_fields) {
            let res: String = res;
            println!("{res}"); // >>> OK
        } else {
            println!("Error setting bike:1");
        }

        match r.hget("bike:1", "model") {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> Deimos
            },
            Err(e) => {
                println!("Error getting bike:1 model: {e}");
                return;
            }
        }

        match r.hget("bike:1", "price") {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> 4972
            },
            Err(e) => {
                println!("Error getting bike:1 price: {e}");
                return;
            }
        }

        match r.hgetall("bike:1") {
            Ok(res) => {
                let res: Vec<(String, String)> = res;

                for (key, value) in res {
                    println!("{key}: {value}");
                }
                // >>> model: Deimos
                // >>> brand: Ergonom
                // >>> type: Enduro bikes
                // >>> price: 4972
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        }
    }
}


title: Connect to Azure Managed Redis

summary: Learn how to authenticate to an Azure Managed Redis (AMR) database

title: Overview

text:
The [`redis-authx-entraid`](https://github.com/redis/jvm-redis-authx-entraid) package
lets you authenticate your app to
[Azure Managed Redis (AMR)](https://azure.microsoft.com/en-us/products/managed-redis)
using [Microsoft Entra ID](https://learn.microsoft.com/en-us/entra/identity/).
You can authenticate using a system-assigned or user-assigned
[managed identity](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview)
or a [service principal](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals),
letting `redis-authx-entraid` fetch and renew the authentication tokens for you automatically.

See
[Use Microsoft Entra for cache authentication](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/cache-azure-active-directory-for-authentication)
in the Microsoft docs to learn how to configure Azure to use Entra ID authentication.

title: Install

text:
Install [`jedis`]() first,
if you have not already done so.

If you are using Maven, add
the following dependency to your `pom.xml` file:

[code example]

If you are using Gradle, add the following dependency to your
`build.gradle` file:

[code example]

title: Create a `TokenAuthConfig` instance

text:
The `TokenAuthConfig` class contains the authentication details that you
must supply when you connect to Redis. Chain the methods of the
`EntraIDTokenAuthConfigBuilder` class together (starting with the `builder()`
method) to include the details you need, as shown in the following example:

[code example]

Some of the details you can supply are common to different use cases:

-   `secret()`: A string containing the [authentication secret](https://learn.microsoft.com/en-us/purview/sit-defn-azure-ad-client-secret).
-   `authority()`: A string containing the [authority](https://learn.microsoft.com/en-us/entra/identity-platform/msal-client-application-configuration#authority)
    URL.
-   `scopes()`: A set of strings defining the [scopes](https://learn.microsoft.com/en-us/entra/identity-platform/scopes-oidc)
    you want to apply. Configure your client application to acquire a Microsoft Entra token for scope, `https://redis.azure.com/.default` or `acca5fbb-b7e4-4009-81f1-37e38fd66d78/.default` (as detailed at [Microsoft Entra ID for authentication](https://learn.microsoft.com/en-us/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#microsoft-entra-client-workflow))
    with the
    [Microsoft Authentication Library (MSAL)](https://learn.microsoft.com/en-us/entra/identity-platform/msal-overview)

(See [Advanced configuration options](#advanced-configuration-options) below
to learn more about the options for controlling token request retry and timeout
behavior.)

You can also add configuration to authenticate with a [service principal](#serv-principal)
or a [managed identity](#mgd-identity) as described in the sections below.

title: Configuration for a service principal {#serv-principal}

role: configuration

text:
Add `clientId()` to the `EntraIDTokenAuthConfigBuilder` chain to specify
authentication via a service principal, passing the ID token string as
a parameter. (See the
[Microsoft EntraID docs](https://learn.microsoft.com/en-us/entra/identity-platform/app-objects-and-service-principals)
for more information about service principals.)

[code example]

title: Configuration for a managed identity {#mgd-identity}

text:
You can also authenticate to AMR using a managed identity (see the
[Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) to learn more about managed identities).

For a system assigned managed identity, simply add the `systemAssignedManagedIdentity()`
method to the `EntraIDTokenAuthConfigBuilder` chain:

[code example]

For a user assigned managed identity, add `userAssignedManagedIdentity()`. This
requires a member of the `UserManagedIdentityType` enum (to select a
`CLIENT_ID`, `OBJECT_ID`, or `RESOURCE_ID`) as well as the `id` string itself:

[code example]

title: Connect using `DefaultJedisClientConfig`

text:
When you have created your `TokenAuthConfig` instance, you are ready to
connect to AMR.
The example below shows how to include the `TokenAuthConfig` details in a
`JedisClientConfig` instance and use it with the `RedisClusterClient` connection.
The connection uses
[Transport Layer Security (TLS)](https://en.wikipedia.org/wiki/Transport_Layer_Security),
which is recommended and enabled by default for managed identities. See
[Connect to your production Redis with TLS]() for more information about
TLS connections, including the implementation of the `createSslSocketFactory()`
method used in the example.

[code example]

title: Advanced configuration options

text:
The `TokenAuthConfig` class has several other options that you can
set with the `EntraIDTokenAuthConfigBuilder.builder()`. These give you
more precise control over the way the token is renewed:

[code example]

These options are explained below:

-  `expirationRefreshRatio`: a `float` value representing the fraction
   of a token's lifetime that should elapse before attempting to
   refresh it. For example, a value of 0.75 means that you want to
   refresh the token after 75% of its lifetime has passed.
-  `lowerRefreshBoundMillis`: the minimum amount of the token's lifetime
   (in milliseconds) remaining before attempting to refresh, regardless
   of the `expirationRefreshRatio` value. Set this to zero if you want
   the refresh time to depend only on `expirationRefreshRatio`.
-  `tokenRequestExecTimeoutInMs`: the maximum time (in milliseconds) to
   wait for a token request to receive a response. A timeout occurs if this limit is exceeded.
-  `maxAttemptsToRetry`: the maximum number of times to retry a token
   request before aborting.
-  `delayInMsToRetry`: the time (in milliseconds) to wait before
    retrying a token request after a failed attempt. This provides a mechanism to request throttling to prevent an excessive number of token requests.

code:
<dependency>
    <groupId>redis.clients.authentication</groupId>
    <artifactId>redis-authx-entraid</artifactId>
    <version>0.1.1-beta1</version>
</dependency>

code:
TokenAuthConfig authConfig = EntraIDTokenAuthConfigBuilder.builder()
        .secret("<secret>")
        .authority("<authority>")
        // Other options...
        .build();

section_id: create-a-tokenauthconfig-instance

code:
TokenAuthConfig authConfig = EntraIDTokenAuthConfigBuilder.builder()
        .clientId("<CLIENT-ID>")
         // ...
        .build();

code:
TokenAuthConfig authConfig = EntraIDTokenAuthConfigBuilder.builder()
        .systemAssignedManagedIdentity()
         // ...
        .build();

code:
TokenAuthConfig authConfig = EntraIDTokenAuthConfigBuilder.builder()
        .userAssignedManagedIdentity(
            UserManagedIdentityType.CLIENT_ID,
            "<ID>"
        )
         // ...
        .build();

code:
TokenAuthConfig authConfig = EntraIDTokenAuthConfigBuilder.builder()
        // Chain of options...
        .build();

SSLSocketFactory sslFactory = createSslSocketFactory(
        "./truststore.jks",
        "secret!", // Use the password you specified for `keytool`
        "./redis-user-keystore.p12",
        "secret!" // Use the password you specified for `openssl`
);

JedisClientConfig config = DefaultJedisClientConfig.builder()
        // Include the `TokenAuthConfig` details.
        .authXManager(new AuthXManager(authConfig))
        .ssl(true).sslSocketFactory(sslFactory)
        .build();

// AMR databases have clustering enabled by default.
RedisClusterClient jedis = RedisClusterClient.builder()
        .hostAndPort(new HostAndPort("<host>", <port>))
        .clientConfig(config)
        .build();

// Test the connection.
System.out.println(String.format("Database size is %d", jedis.dbSize()));

section_id: connect-using-defaultjedisclientconfig

code:
TokenAuthConfig authConfig = EntraIDTokenAuthConfigBuilder.builder()
        .expirationRefreshRatio(0.75)
        .lowerRefreshBoundMillis(100)
        .tokenRequestExecTimeoutInMs(100)
        .maxAttemptsToRetry(10)
        .delayInMsToRetry()
         // ...
        .build();

section_id: advanced-configuration-options


title: Connect to the server

title: Overview

text:
Jedis 7.2.0 introduced a new client connection API:

| New API class | Replaces | Use case |
| :-- | :-- | :-- |
| `RedisClient` | `UnifiedJedis`, `JedisPool`, `JedisPooled` | Single connection (with connection pooling) |
| `RedisClusterClient` | `JedisCluster` | Redis Cluster connections |
| `RedisSentinelClient` | `JedisSentinelPool` | Redis Sentinel connections |

The old client classes are now considered deprecated.

title: Basic connection

text:
The following code opens a basic connection to a local Redis server:

[code example]

After you have connected, you can check the connection by storing and
retrieving a simple string value:

[code example]

title: Connect to a Redis cluster

text:
To connect to a Redis cluster, use `RedisClusterClient`.

[code example]

text:
When you deploy your application, use TLS and follow the [Redis security]() guidelines.

Before connecting your application to the TLS-enabled Redis server, ensure that your certificates and private keys are in the correct format.

To convert user certificate and private key from the PEM format to `pkcs12`, use this command:

[code example]

Enter password to protect your `pkcs12` file.

Convert the server (CA) certificate to the JKS format using the [keytool](https://docs.oracle.com/en/java/javase/12/tools/keytool.html) shipped with JDK.

[code example]

Establish a secure connection with your Redis database using this snippet.

[code example]

title: Connect using client-side caching

text:
Client-side caching is a technique to reduce network traffic between
the client and server, resulting in better performance. See
[Client-side caching introduction]()
for more information about how client-side caching works and how to use it effectively.

To enable client-side caching, specify the
[RESP3]()
protocol and pass a cache configuration object during the connection.

The example below shows the simplest client-side caching connection to the default host and port,
`localhost:6379`.
All of the connection variants described above accept these parameters, so you can
use client-side caching with a connection pool or a cluster connection in exactly the same way.

Client-side caching requires Jedis v5.2.0 or later.
To maximize compatibility with all Redis products, client-side caching
is supported by Redis v7.4 or later.

The [Redis server products]() support
[opt-in/opt-out]() mode
and [broadcasting mode]()
for CSC, but these modes are not currently implemented by Jedis.

[code example]

Once you have connected, the usual Redis commands will work transparently
with the cache:

[code example]

You can see the cache working if you connect to the same Redis database
with [`redis-cli`]() and run the
[`MONITOR`]() command. If you run the
code above but without passing `cacheConfig` during the connection,
you should see the following in the CLI among the output from `MONITOR`:

[code example]

The server responds to both `get("city")` calls.
If you run the code with `cacheConfig` added in again, you will see

[code example]

The first `get("city")` call contacted the server, but the second
call was satisfied by the cache.

title: Removing items from the cache

text:
You can remove individual keys from the cache with the
`deleteByRedisKey()` method of the cache object. This removes all cached items associated
with each specified key, so all results from multi-key commands (such as
[`MGET`]()) and composite data structures
(such as [hashes]()) will be
cleared at once. The example below shows the effect of removing a single
key from the cache:

[code example]

You can also clear all cached items using the `flush()`
method:

[code example]

The client will also flush the cache automatically
if any connection (including one from a connection pool)
is disconnected.

title: Configure a connection pool

text:
A connection pool maintains several open connections and reuses them
efficiently. When you open a connection from a pool, the pool allocates
one of its open connections. When you subsequently close the same connection,
it is not actually closed but simply returned to the pool for reuse.
This avoids the overhead of repeated connecting and disconnecting.
See
[Connection pools and multiplexing]()
for more information.

From Jedis 7.2.0, the `RedisClient` class provides connection pooling automatically,
but it's important to configure the connection pool correctly to get the best performance.
Each pool holds a specified number of connections, creates more connections when necessary, and terminates them when they are no longer needed.

Here is a simplified connection lifecycle in a pool:

1. A connection is requested from the pool.
2. A connection is served:
   - An idle connection is served when non-active connections are available, or
   - A new connection is created when the number of connections is under `maxTotal`.
3. The connection becomes active.
4. The connection is released back to the pool.
5. The connection is marked as stale.
6. The connection is kept idle for `minEvictableIdleTime`.
7. The connection becomes evictable if the number of connections is greater than `minIdle`.
8. The connection is ready to be closed.

Pass a `ConnectionPoolConfig` object to the `RedisClient` builder to configure the pool.
(`ConnectionPoolConfig` is a wrapper around `GenericObjectPoolConfig` from [Apache Commons Pool2](https://commons.apache.org/proper/commons-pool/apidocs/org/apache/commons/pool2/impl/GenericObjectPoolConfig.html)).

[code example]

title: Retrying a command after a connection failure

text:
If a connection is lost before a command is completed, the command will fail with a `JedisConnectionException`. Although the connection pool manages the connections
for you, you must request a new connection from the pool to retry the command.
You would typically do this in a loop that makes several attempts to reconnect
before aborting and reporting that the error isn't transient. The example below
shows a retry loop that uses a simple
[exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff)
strategy:

[code example]

code:
package org.example;
import redis.clients.jedis.RedisClient;

public class Main {
    public static void main(String[] args) {
        RedisClient jedis = RedisClient.create("redis://localhost:6379");

        // Code that interacts with Redis...

        jedis.close();
    }
}

code:
...

String res1 = jedis.set("bike:1", "Deimos");
System.out.println(res1); // OK

String res2 = jedis.get("bike:1");
System.out.println(res2); // Deimos

...

code:
import redis.clients.jedis.RedisClusterClient;
import redis.clients.jedis.HostAndPort;

//...

Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>();
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7379));
jedisClusterNodes.add(new HostAndPort("127.0.0.1", 7380));
RedisClusterClient jedis = RedisClusterClient.create(jedisClusterNodes);

code: openssl pkcs12 -export -in ./redis_user.crt -inkey ./redis_user_private.key -out redis-user-keystore.p12 -name "redis"

code:
keytool -importcert -keystore truststore.jks \
  -storepass REPLACE_WITH_YOUR_PASSWORD \
  -file redis_ca.pem

code:
package org.example;

import redis.clients.jedis.*;

import javax.net.ssl.*;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;

public class Main {

    public static void main(String[] args) throws GeneralSecurityException, IOException {
        HostAndPort address = new HostAndPort("my-redis-instance.cloud.redislabs.com", 6379);

        SSLSocketFactory sslFactory = createSslSocketFactory(
                "./truststore.jks",
                "secret!", // use the password you specified for keytool command
                "./redis-user-keystore.p12",
                "secret!" // use the password you specified for openssl command
        );

        JedisClientConfig config = DefaultJedisClientConfig.builder()
                .ssl(true).sslSocketFactory(sslFactory)
                .user("default") // use your Redis user. More info https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/
                .password("secret!") // use your Redis password
                .build();

        RedisClient jedis = RedisClient.builder()
              .hostAndPort(address)
              .clientConfig(config)
              .build();
        jedis.set("foo", "bar");
        System.out.println(jedis.get("foo")); // prints bar
    }

    private static SSLSocketFactory createSslSocketFactory(
            String caCertPath, String caCertPassword, String userCertPath, String userCertPassword)
            throws IOException, GeneralSecurityException {

        KeyStore keyStore = KeyStore.getInstance("pkcs12");
        keyStore.load(new FileInputStream(userCertPath), userCertPassword.toCharArray());

        KeyStore trustStore = KeyStore.getInstance("jks");
        trustStore.load(new FileInputStream(caCertPath), caCertPassword.toCharArray());

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("X509");
        trustManagerFactory.init(trustStore);

        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
        keyManagerFactory.init(keyStore, userCertPassword.toCharArray());

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);

        return sslContext.getSocketFactory();
    }
}

code:
HostAndPort endpoint = new HostAndPort("localhost", 6379);

DefaultJedisClientConfig config = DefaultJedisClientConfig
    .builder()
    .password("secretPassword")
    .protocol(RedisProtocol.RESP3)
    .build();

CacheConfig cacheConfig = CacheConfig.builder().maxSize(1000).build();

RedisClient client = RedisClient.builder()
        .hostAndPort(endpoint)
        .clientConfig(config)
        .cacheConfig(cacheConfig)
        .build();

section_id: connect-using-client-side-caching

code:
client.set("city", "New York");
client.get("city");     // Retrieved from Redis server and cached
client.get("city");     // Retrieved from cache

code:
client.hget("person:1", "name");    // Read from the server
client.hget("person:1", "name");    // Read from the cache

client.hget("person:2", "name");    // Read from the server
client.hget("person:2", "name");    // Read from the cache

Cache myCache = client.getCache();
myCache.deleteByRedisKey("person:1");

client.hget("person:1", "name");    // Read from the server
client.hget("person:1", "name");    // Read from the cache

client.hget("person:2", "name");    // Still read from the cache

section_id: removing-items-from-the-cache

code:
client.hget("person:1", "name");    // Read from the server
client.hget("person:1", "name");    // Read from the cache

client.hget("person:2", "name");    // Read from the server
client.hget("person:2", "name");    // Read from the cache

Cache myCache = client.getCache();
myCache.flush();

client.hget("person:1", "name");    // Read from the server
client.hget("person:1", "name");    // Read from the cache

client.hget("person:2", "name");    // Read from the server
client.hget("person:2", "name");    // Read from the cache

code:
ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
// maximum active connections in the pool,
// tune this according to your needs and application type
// default is 8
poolConfig.setMaxTotal(8);

// maximum idle connections in the pool, default is 8
poolConfig.setMaxIdle(8);
// minimum idle connections in the pool, default 0
poolConfig.setMinIdle(0);

// Enables waiting for a connection to become available.
poolConfig.setBlockWhenExhausted(true);
// The maximum number of seconds to wait for a connection to become available
poolConfig.setMaxWait(Duration.ofSeconds(1));

// Enables sending a PING command periodically while the connection is idle.
poolConfig.setTestWhileIdle(true);
// controls the period between checks for idle connections in the pool
poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));

RedisClient jedis = RedisClient.builder()
        .hostAndPort("localhost", 6379)
        .poolConfig(poolConfig)
        .build();

section_id: configure-a-connection-pool

code:
RedisClient jedis = RedisClient.builder()
        .hostAndPort("localhost", 6379)
        .poolConfig(poolConfig)
        .clientConfig(config)
        .build();

// Set max retry attempts
final int MAX_RETRIES = 5;

// Example of retrying a command
String key = "retry-example";
String value = "success";

int attempts = 0;
boolean success = false;

while (!success && attempts < MAX_RETRIES) {
    try {
        attempts++;
        String result = jedis.set(key, value);
        System.out.println("Command succeeded on attempt " + attempts + ": " + result);
        success = true;
    } catch (JedisConnectionException e) {
        System.out.println("Connection failed on attempt " + attempts + ": " + e.getMessage());
        if (attempts >= MAX_RETRIES) {
            System.out.println("Max retries reached. Giving up.");
            throw e;
        }

        // Wait before retrying
        try {
            Thread.sleep(500 * attempts); // Exponential backoff
        } catch (InterruptedException ie) {
            Thread.currentThread().interrupt();
        }
    }
}


title: Error handling

summary: Learn how to handle errors when using Jedis.

title: Overview

text:
Jedis uses **exceptions** to signal errors. Code examples in the documentation often omit error handling for brevity, but it is essential in production code. This page explains how Jedis's error handling works and how to apply common error handling patterns.

For an overview of error types and handling strategies, see [Error handling]().
See also [Production usage]()
for more information on connection management, timeouts, and other aspects of
app reliability.

title: Exception hierarchy

role: errors

text:
Jedis organizes exceptions in a hierarchy rooted at `JedisException`, which extends `RuntimeException`. All Jedis exceptions are unchecked exceptions:

[code example]

title: Key exceptions

text:
The following exceptions are the most commonly encountered in Jedis applications.
See [Categories of errors]()
for a more detailed discussion of these errors and their causes.

| Exception | When it occurs | Recoverable | Recommended action |
|---|---|---|---|
| `JedisConnectionException` | Connection lost or closed unexpectedly | ✅ | Retry with backoff or fall back |
| `JedisAccessControlException` | Authentication failure or permission denied | ❌ | Fix credentials or permissions |
| `JedisDataException` | Problem with data being sent or received | ❌ | Fix the data or command |
| `JedisException` | Unexpected errors (catch-all) | ❌ | Log and investigate |

title: Applying error handling patterns

text:
The [Error handling]() overview
describes four main patterns. The sections below show how to implement them in
Jedis:

title: Pattern 1: Fail fast

text:
Catch specific exceptions that represent unrecoverable errors and re-throw them (see
[Pattern 1: Fail fast]()
for a full description):

[code example]

title: Pattern 2: Graceful degradation

text:
Catch specific errors and fall back to an alternative, where possible (see
[Pattern 2: Graceful degradation]()
for a full description):

[code example]

title: Pattern 3: Retry with backoff

text:
Retry on temporary errors like connection failures (see
[Pattern 3: Retry with backoff]()
for a full description):

[code example]

title: Pattern 4: Log and continue

text:
Log non-critical errors and continue (see
[Pattern 4: Log and continue]()
for a full description):

[code example]

title: See also

role: related

text:
- [Error handling]()
- [Production usage]()

code:
"JedisException":
    _meta:
        description: "Base class for all Jedis exceptions"
    "JedisDataException":
        "JedisRedirectionException":
            "JedisMovedDataException":
            "JedisAskDataException":
        "AbortedTransactionException":
        "JedisAccessControlException":
        "JedisNoScriptException":
    "JedisClusterException":
        "JedisClusterOperationException":
        "JedisConnectionException":
        "JedisValidationException":
    "InvalidURIException":

section_id: exception-hierarchy

code:
try (RedisClient jedis = RedisClient.create()) {
    String result = jedis.get(key);
} catch (JedisDataException e) {
    // This indicates a bug in our code
    throw e;
}

code:
try (RedisClient jedis = RedisClient.create()) {
    String cachedValue = jedis.get(key);
    if (cachedValue != null) {
        return cachedValue;
    }
} catch (JedisConnectionException e) {
    logger.warn("Cache unavailable, using database");
    return database.get(key);
}

// Fallback to database
return database.get(key);

code:
int maxRetries = 3;
int retryDelay = 100;

for (int attempt = 0; attempt < maxRetries; attempt++) {
    try (RedisClient jedis = RedisClient.create()) {
        return jedis.get(key);
    } catch (JedisConnectionException e) {
        if (attempt < maxRetries - 1) {
            try {
                Thread.sleep(retryDelay);
                retryDelay *= 2;  // Exponential backoff
            } catch (InterruptedException ie) {
                Thread.currentThread().interrupt();
                throw new RuntimeException(ie);
            }
        } else {
            throw e;
        }
    }
}

code:
try (RedisClient jedis = RedisClient.create()) {
    jedis.setex(key, 3600, value);
} catch (JedisConnectionException e) {
    logger.warn("Failed to cache " + key + ", continuing without cache");
    // Application continues normally
}


title: Client-side geographic failover

summary: Improve reliability using the failover features of Jedis.

title: Overview

text:
Jedis supports [Client-side geographic failover](https://en.wikipedia.org/wiki/Failover)
to improve the availability of connections to Redis databases. This page explains
how to configure Jedis for failover. For an overview of the concepts,
see the main [Client-side geographic failover]() page.

title: Failover configuration

text:
Jedis uses the [resilience4j](https://resilience4j.readme.io/docs/getting-started)
library to detect connection problems using a
[circuit breaker design pattern](https://en.wikipedia.org/wiki/Circuit_breaker_design_pattern).

The example below shows a simple case with a list of two servers,
`redis-east` and `redis-west`, where `redis-east` is the preferred
target. If `redis-east` fails, Jedis should fail over to
`redis-west`.

Jedis v6 supported failover/failback using a special
`UnifiedJedis` constructor. You should update existing code to use
the approach shown below for Jedis v7 and later.

First, add the `resilience4j` dependencies to your project. If you
are using [Maven](https://maven.apache.org/), add the following
dependencies to your `pom.xml` file:

[code example]

If you are using [Gradle](https://gradle.org/), add the following
dependencies to your `build.gradle` file:

[code example]

In your source file, create some simple configuration for the client and
[connection pool](),
as you would for a standard connection.

[code example]

Supply the weighted list of endpoints using the `MultiDbConfig` builder
(see [Selecting a failover target]() for a full description of how
the weighted list is used).
Use the `weight` option to order the endpoints, with the highest
weight being tried first.

[code example]

The builder lets you add several options to configure the
[circuit breaker](#circuit-breaker-configuration) behavior
and [retries](#retry-configuration) (these are explained in more detail below).

[code example]

Finally, use the configuration to build the `MultiDbClient`.

[code example]

Like `UnifiedJedis`, `MultiDbClient` implements the usual Redis commands,
but will also handle the connection management and failover transparently.

title: Circuit breaker configuration

text:
The `MultiDbConfig.CircuitBreakerConfig` builder lets you pass several options to configure
the circuit breaker (see [Detecting connection problems]() for more information on how the
circuit breaker works):

| Builder method | Default value | Description|
| --- | --- | --- |
| `slidingWindowSize()` | `2` | Duration in seconds to keep failures and successes in the sliding window. |
| `minNumOfFailures()` | `1000` | Minimum number of failures that must occur before the circuit breaker is tripped. |
| `failureRateThreshold()` | `10.0f` | Percentage of failures to trigger the circuit breaker. |
| `includedExceptionList()` | See description | `List` of `Throwable` classes that should be considered as failures. By default, it includes just `JedisConnectionException`. |
| `ignoreExceptionList()` | `null` | `List` of `Throwable` classes that should be ignored for failure rate calculation. |

title: Retry configuration

text:
The `MultiDbConfig.RetryConfig` builder has the following options to configure retries:

| Builder method | Default value | Description|
| --- | --- | --- |
| `maxAttempts()` | `3` | Maximum number of retry attempts (including the initial call). Set to `1` to disable retries. |
| `waitDuration()` | `500` | Initial number of milliseconds to wait between retry attempts. |
| `exponentialBackoffMultiplier()` | `2` | [Exponential backoff](https://en.wikipedia.org/wiki/Exponential_backoff) factor multiplied by the wait duration between retries. For example, with a wait duration of 1 second and a multiplier of 2, the retries would occur after 1s, 2s, 4s, 8s, 16s, and so on. |
| `includedExceptionList()` | See description | `List` of `Throwable` classes that should be considered as failures to be retried. By default, it includes just `JedisConnectionException`. |
| `ignoreExceptionList()` | `null` | `List` of `Throwable` classes that should be ignored for retry. |

title: General failover configuration

text:
The `MultiDbConfig` builder also has the following options to configure general failover behavior:

| Builder method | Default value | Description|
| --- | --- | --- |
| `maxNumFailoverAttempts()` | `10` | Number of attempts to fail over to a new endpoint before giving up. |
| `delayInBetweenFailoverAttempts()` | `12000` | Time interval in milliseconds between successive failover attempts. |
| `gracePeriod()` | `60000` | Time interval in milliseconds to keep the unhealthy endpoint disabled even if it recovers (this prevents rapid oscillation between endpoints when intermittent faults occur). |
| `fastFailover()` | `false` | If true, existing connections to an unhealthy endpoint are forced to close immediately when a failover occurs, otherwise the connections are closed gracefully. Forcefully closing connections can make failover faster, but it might also cause in-flight operations to fail. |
| `retryOnFailover()` | `false` | If true, commands that fail during a failover are automatically retried on the replacement endpoint. |

title: Failover callbacks

text:
You may want to take some custom action when a failover occurs.
For example, you could log a warning, increment a metric,
or externally persist the cluster connection state.

You can provide a custom failover action using a class that
implements `java.util.function.Consumer`. Place
the custom action in the `accept()` method, as shown in the example below.

[code example]

Use the `databaseSwitchListener()` method of the `MultiDbClient` builder to
register your custom action:

[code example]

Your `accept()` method is now called whenever a failover occurs.

Since `Consumer` is a functional interface, you can also use a lambda
expression to supply the custom action directly.

[code example]

title: Failback configuration

text:
The `MultiDbConfig` builder lets you configure the failback behavior using the following options:

| Builder method | Default value | Description|
| --- | --- | --- |
| `failbackSupported()` | `true` | Enable/disable failback (it is enabled by default). |
| `failbackCheckInterval()` | `120000` | Interval in milliseconds to check if the unhealthy database has recovered. |

title: Health check configuration

text:
Each health check consists of one or more separate "probes", each of which is a simple
test (such as a [`PING`]() command) to determine if the database is available. The results of the separate probes are combined
using a configurable policy to determine if the database is healthy.

There are several strategies available for health checks that you can deploy using the
`MultiDbConfig` builder. Each strategy is a class that implements the `HealthCheckStrategy`
interface. Use the constructor of a `HealthCheckStrategy` implementation to pass
a `HealthCheckStrategy.Config` object to configure the health check behavior.
The methods of the base `HealthCheckStrategy.Config` builder are shown below.
Note that some strategies (including your own custom strategies) may use a
subclass of `HealthCheckStrategy.Config` to provide extra options.

| Builder method | Default value | Description|
| --- | --- | --- |
| `interval()` | `1000` | Interval in milliseconds between health checks. |
| `timeout()` | `1000` | Timeout in milliseconds for health check requests. |
| `numProbes()` | `3` | Number of probes to perform during each health check. |
| `delayInBetweenProbes()` | `100` | Delay in milliseconds between probes during a health check. |
| `policy()` | `ProbingPolicy.BuiltIn.ALL_SUCCESS` | Policy to determine if the database is healthy based on the probe results. The options are `ALL_SUCCESS` (all probes must succeed), `ANY_SUCCESS` (at least one probe must succeed), and `MAJORITY_SUCCESS` (majority of probes must succeed). |

The sections below explain the available strategies in more detail.

title: `PingStrategy` (default)

text:
The default strategy, `PingStrategy`, periodically sends a Redis
[`PING`]() command
and checks that it gives the expected response. Any unexpected response
or exception indicates an unhealthy server. Although `PingStrategy` is
very simple, it is a good basic approach for most Redis deployments.

Although `PingStrategy` is the default, you can still activate it
explicitly using the `healthCheckStrategy()` method of the `MultiDbConfig.DatabaseConfig`
builder. Use this approach if you want to configure the default
`PingStrategy` with custom options, as shown in the example below.

[code example]

title: `LagAwareStrategy` (preview)

text:
`LagAwareStrategy` (currently in preview) is designed specifically for
Redis Software [Active-Active]()
deployments. It uses the Redis Software REST API to check database availability
and can also optionally check replication lag.

`LagAwareStrategy` determines the health of the server using the
[REST API](). The example
below shows how to configure `LagAwareStrategy` and activate it using
the `healthCheckStrategy()` method of the `MultiDbConfig.DatabaseConfig`
builder.

[code example]

The `LagAwareStrategy.Config` builder has the following options in
addition to the standard options provided by `HealthCheckStrategy.Config`:

| Builder method | Default value | Description|
| --- | --- | --- |
| `sslOptions()` | `null` | Standard SSL options for connecting to the REST API. |
| `extendedCheckEnabled()` | `false` | Enable extended lag checking (this includes lag validation in addition to the standard datapath validation). |
| `availabilityLagTolerance()` | `100` | Maximum lag tolerance in milliseconds for extended lag checking. |

title: Custom health check strategy

text:
You can supply your own custom health check strategy by
implementing the `HealthCheckStrategy` interface. For example, you might
use this to integrate with external monitoring tools or to implement
checks that are specific to your application. The example below
shows a simple custom strategy. Pass your custom strategy implementation to the `MultiDbConfig.DatabaseConfig`
builder with the `healthCheckStrategySupplier()` method.

[code example]

title: Disable health checks

text:
To disable health checks completely, use the
`healthCheckEnabled()` method of the `MultiDbConfig.DatabaseConfig`
builder:

[code example]

title: Managing databases at runtime

text:
Although you will typically configure all databases during the initial connection, you can also modify the configuration at runtime. The example below shows how to add and remove database endpoints.

[code example]

title: Manual failback

text:
By default, the failback mechanism runs health checks on all servers in the
weighted list and selects the highest-weighted server that is
healthy. However, you can also use the `setActiveDatabase()` method of
`MultiDbClient` to select which database to use manually:

[code example]

Note that `setActiveDatabase()` is thread-safe.

If you decide to implement manual failback, you will need a way for external
systems to trigger this method in your application. For example, if your application
exposes a REST API, you might consider creating a REST endpoint to call
`setActiveDatabase()`.

title: Behavior when all endpoints are unhealthy

text:
In the extreme case where no endpoint is healthy, a command will throw a
`JedisTemporarilyNotAvailableException`. This indicates that the client is periodically
checking to see if any endpoint becomes healthy again. The number of
times it will keep checking is configured by the `maxNumFailoverAttempts()` option in
the `MultiDbConfig` builder and
the delay between attempts is configured by the `delayInBetweenFailoverAttempts()` option (see [General failover configuration](#general-failover-configuration)). With the default settings,
`maxNumFailoverAttempts` * `delayInBetweenFailoverAttempts`  gives a period of 120 seconds to find
a healthy endpoint.

You can still keep retrying commands after a `JedisTemporarilyNotAvailableException` is thrown (for example,
you could add this exception to the `includedExceptionList`, as described
in the [Retry configuration]() section). However, if the number of
failover attempts exceeds the value set by `maxNumFailoverAttempts()`, commands will throw a `JedisPermanentlyNotAvailableException`. Note that this is intended to notify your app
that the problem is likely to be persistent, but it *doesn't* mean that Jedis will stop trying
to connect to a healthy endpoint if one becomes available.

title: Troubleshooting

text: This section lists some common problems and their solutions.

title: Excessive or constant health check failures

text:
If all health checks fail, you should first rule out authentication
problems with the Redis server and also make sure there are no persistent
network connectivity problems. If you still see frequent or constant
failures, try increasing the timeout for health checks and the
interval between them:

[code example]

title: Slow failback after recovery

text:
If failback is too slow after a server recovers, you can try
increasing the frequency of health checks and reducing the grace
period before failback is attempted (the grace period is the
minimum time after a failover before Jedis will check if a
failback is possible).

[code example]

code:
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-all</artifactId>
    <version>1.7.1</version>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-circuitbreaker</artifactId>
    <version>1.7.1</version>
</dependency>
<dependency>
    <groupId>io.github.resilience4j</groupId>
    <artifactId>resilience4j-retry</artifactId>
    <version>1.7.1</version>
</dependency>

section_id: failover-configuration

code:
JedisClientConfig config = DefaultJedisClientConfig.builder().user("<username>").password("<password>")
    .socketTimeoutMillis(5000).connectionTimeoutMillis(5000).build();

ConnectionPoolConfig poolConfig = new ConnectionPoolConfig();
poolConfig.setMaxTotal(8);
poolConfig.setMaxIdle(8);
poolConfig.setMinIdle(0);
poolConfig.setBlockWhenExhausted(true);
poolConfig.setMaxWait(Duration.ofSeconds(1));
poolConfig.setTestWhileIdle(true);
poolConfig.setTimeBetweenEvictionRuns(Duration.ofSeconds(1));

code:
HostAndPort east = new HostAndPort("redis-east.example.com", 14000);
HostAndPort west = new HostAndPort("redis-west.example.com", 14000);

MultiDbConfig.Builder multiConfig = MultiDbConfig.builder()
        .database(DatabaseConfig.builder(east, config).connectionPoolConfig(poolConfig).weight(1.0f).build())
        .database(DatabaseConfig.builder(west, config).connectionPoolConfig(poolConfig).weight(0.5f).build());

code:
// Configure circuit breaker for failure detection
multiConfig
        .failureDetector(MultiDbConfig.CircuitBreakerConfig.builder()
                .slidingWindowSize(2)        // Sliding window size as a duration in seconds.
                .failureRateThreshold(10.0f)    // Percentage of failures to trigger circuit breaker.
                .minNumOfFailures(1000)          // Minimum number of failures before circuit breaker is tripped.
                .build())
        .failbackSupported(true)                // Enable failback.
        .failbackCheckInterval(120000)          // Check every 2 minutes to see if the unhealthy database has recovered.
        .gracePeriod(60000)                     // Keep database disabled for 60 seconds after it becomes unhealthy.
        // Optional: configure retry settings
        .commandRetry(MultiDbConfig.RetryConfig.builder()
                .maxAttempts(3)                  // Maximum number of retry attempts (including the initial call)
                .waitDuration(500)               // Number of milliseconds to wait between retry attempts.
                .exponentialBackoffMultiplier(2) // Exponential backoff factor multiplied by the wait duration between retries.
                .build())
        // Optional: configure fast failover
        .fastFailover(true)                       // Force closing connections to unhealthy database on failover.
        .retryOnFailover(false);                  // Do not retry failed commands during failover.

code:
MultiDbClient multiDbClient = MultiDbClient.builder()
        .multiDbConfig(multiConfig.build())
        .build();

code:
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.function.Consumer;

public class FailoverReporter implements Consumer<DatabaseSwitchEvent> {

    @Override
    public void accept(DatabaseSwitchEvent e) {
        System.out.println("Jedis failover to database: " + e.getDatabaseName() + " due to " + e.getReason());
    }
}

section_id: failover-callbacks

code:
FailoverReporter reporter = new FailoverReporter();
MultiDbClient client = MultiDbClient.builder()
        .databaseSwitchListener(reporter)
        .build();

code:
MultiDbClient client = MultiDbClient.builder()
        .databaseSwitchListener(
            event -> System.out.println("Switched to: " + event.getEndpoint())
        )
        .build();

code:
MultiDbConfig.DatabaseConfig dbConfig =
        MultiDbConfig.DatabaseConfig.builder(hostAndPort, clientConfig)
                .healthCheckStrategy(new PingStrategy(PingStrategy.Config.builder()
                        .interval(5000) // Check every 5 seconds
                        .timeout(3000) // 3 second timeout
                        .numProbes(5) // 5 probes per check
                        .delayInBetweenProbes(100) // 100ms delay between probes
                        .build()))
                .build();

section_id: pingstrategy-default

code:
// Configure REST API endpoint and credentials
HostAndPort restEndpoint = new HostAndPort("redis-enterprise-db-fqdn", 9443);
Supplier<RedisCredentials> credentialsSupplier = () -> new DefaultRedisCredentials("rest-api-user", "pwd");

// Build a single LagAwareStrategy based on REST endpoint and credentials
LagAwareStrategy.Config lagConfig = LagAwareStrategy.Config
        .builder(restEndpoint, credentialsSupplier)
        .interval(5000) // Check every 5 seconds
        .timeout(3000) // 3 second timeout
        .extendedCheckEnabled(true)
        .build();

// Configure a database to use lag-aware health check
MultiDbConfig.DatabaseConfig dbConfig =
        MultiDbConfig.DatabaseConfig.builder(hostAndPort, clientConfig)
                .healthCheckStrategy(new LagAwareStrategy(lagConfig))
                .build();

section_id: lagawarestrategy-preview

code:
// Custom strategy supplier
MultiDbConfig.StrategySupplier customStrategy =
        (hostAndPort, jedisClientConfig) -> {
            // Return your custom HealthCheckStrategy implementation
            return new MyCustomHealthCheckStrategy(hostAndPort, jedisClientConfig);
        };

MultiDbConfig.DatabaseConfig dbConfig =
        MultiDbConfig.DatabaseConfig.builder(hostAndPort, clientConfig)
                .healthCheckStrategySupplier(customStrategy)
                .weight(1.0f)
                .build();

section_id: custom-health-check-strategy

code:
MultiDbConfig.DatabaseConfig dbConfig = MultiDbConfig.DatabaseConfig.builder(east, config)
    .healthCheckEnabled(false) // Disable health checks entirely
    .build();

section_id: disable-health-checks

code:
HostAndPort other = new HostAndPort("redis-south.example.com", 14000);

// Create the database config as you would for the initial connection.
client.addDatabase(DatabaseConfig.builder(other, config)
        // ...
        .weight(0.5f)
        .build()
);

// Remove the database from the failover set.
client.removeDatabase(other);

section_id: managing-databases-at-runtime

code:
// The `setActiveDatabase()` method receives the `Endpoint` (eg,`HostAndPort`)
// of the cluster to switch to.
client.setActiveDatabase(west);

section_id: manual-failback

code:
HealthCheckStrategy.Config config = HealthCheckStrategy.Config.builder()
    .interval(5000)                 // Less frequent checks
    .timeout(2000)                  // More generous timeout
    .build();

code:
// Faster recovery configuration
HealthCheckStrategy.Config config = HealthCheckStrategy.Config.builder()
    .interval(1000)                    // More frequent checks
    .build();

// Adjust failback timing
MultiDbConfig multiConfig = MultiDbConfig.builder()
        .gracePeriod(5000)                 // Shorter grace period
        .build();

section_id: slow-failback-after-recovery


title: Jedis guide (Java)

summary: Connect your Java application to a Redis database

title: Connect to the server

title: Connect to Azure Managed Redis

summary: Learn how to use Redis Search with JSON and hash documents.

title: Index and query documents

summary: Learn how to index and query vector embeddings with Redis

title: Index and query vectors

summary: Index and query embeddings with Redis vector sets

title: Vector set embeddings

summary: Learn how to use Redis pipelines and transactions

title: Pipelines and transactions

summary: Learn how to use approximate calculations with Redis.

title: Probabilistic data types

title: Error handling

title: Client-side geographic failover

summary: Get your Jedis app ready for production

title: Production usage

title: Install

text:
To include `Jedis` as a dependency in your application, edit the dependency file, as follows.

* If you use **Maven**:

  [code example]

* If you use **Gradle**:

  [code example]

* If you use the JAR files, download the latest Jedis and Apache Commons Pool2 JAR files from [Maven Central](https://central.sonatype.com/) or any other Maven repository.

* Build from [source](https://github.com/redis/jedis)

title: Connect and test

text:
Add the following imports to your source file:

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

Connect to localhost on port 6379:

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

After you have connected, you can check the connection by storing and
retrieving a simple [string]() value:

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

Store and retrieve a [hash]():

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

Close the connection when you're done:

#### Code Examples

**Redis CLI:**

[code example]

**Available in:** Redis CLI, C, C# (Asynchronous), C# (Synchronous), Go, Java, Java (Synchronous - Jedis), JavaScript (Node.js), JavaScript (Node.js), PHP, Python, Ruby, Rust (Asynchronous), Rust (Synchronous)

**C:**

[code example]

**C# (Asynchronous):**

[code example]

**C# (Synchronous):**

[code example]

**Go:**

[code example]

**Java:**

[code example]

**Java (Synchronous - Jedis):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**JavaScript (Node.js):**

[code example]

**PHP:**

[code example]

**Python:**

[code example]

**Ruby:**

[code example]

**Rust (Asynchronous):**

[code example]

**Rust (Synchronous):**

[code example]

title: More information

text:
`Jedis` has a complete [API reference](https://www.javadoc.io/doc/redis.clients/jedis/latest/index.html) available on [javadoc.io/](https://javadoc.io/).
The `Jedis` [GitHub repository](https://github.com/redis/jedis) also has useful docs
and examples including a page about handling
[failover with Jedis](https://github.com/redis/jedis/blob/master/docs/failover.md)

See also the other pages in this section for more information and examples:

code:
<dependency>
      <groupId>redis.clients</groupId>
      <artifactId>jedis</artifactId>
      <version>7.2.0</version>
  </dependency>

section_id: install

code:
repositories {
      mavenCentral()
  }
  //...
  dependencies {
      implementation 'redis.clients:jedis:7.2.0'
      //...
  }

code:
#include <stdio.h>
#include <stdlib.h>

#include <hiredis/hiredis.h>

int main() {
    // The `redisContext` type represents the connection
    // to the Redis server. Here, we connect to the
    // default host and port.
    redisContext *c = redisConnect("127.0.0.1", 6379);

    // Check if the context is null or if a specific
    // error occurred.
    if (c == NULL || c->err) {
        if (c != NULL) {
            printf("Error: %s\n", c->errstr);
            // handle error
        } else {
            printf("Can't allocate redis context\n");
        }

        exit(1);
    }

    // Set a string key.
    redisReply *reply = redisCommand(c, "SET foo bar");
    printf("Reply: %s\n", reply->str); // >>> Reply: OK
    freeReplyObject(reply);

    // Get the key we have just stored.
    reply = redisCommand(c, "GET foo");
    printf("Reply: %s\n", reply->str); // >>> Reply: bar
    freeReplyObject(reply);

    // Close the connection.
    redisFree(c);
}

section_id: connect-and-test

code:
import (
	"context"
	"fmt"

	"github.com/redis/go-redis/v9"
)

code:
import redis.clients.jedis.RedisClient;
import java.util.HashMap;
import java.util.Map;

code:
import { createClient } from 'redis';

const client = createClient();

client.on('error', err => console.log('Redis Client Error', err));

await client.connect();

await client.set('key', 'value');
const value = await client.get('key');
console.log(value); // >>> value

await client.hSet('user-session:123', {
    name: 'John',
    surname: 'Smith',
    company: 'Redis',
    age: 29
})

let userSession = await client.hGetAll('user-session:123');
console.log(JSON.stringify(userSession, null, 2));
/* >>>
{
  "surname": "Smith",
  "name": "John",
  "company": "Redis",
  "age": "29"
}
 */

await client.quit();

code:
import { Redis } from 'ioredis';

const redis = new Redis();

await redis.set('key', 'value');
const value = await redis.get('key');
console.log(value); // >>> value

await redis.hset('user-session:123', {
    name: 'John',
    surname: 'Smith',
    company: 'Redis',
    age: 29
});

const userSession = await redis.hgetall('user-session:123');
console.log(JSON.stringify(userSession, null, 2));
/* >>>
{
  "surname": "Smith",
  "name": "John",
  "company": "Redis",
  "age": "29"
}
 */

redis.disconnect();

code:
<?php

require 'vendor/autoload.php';

use Predis\Client as PredisClient;

$r = new PredisClient([
                'scheme'   => 'tcp',
                'host'     => '127.0.0.1',
                'port'     => 6379,
                'password' => '',
                'database' => 0,
            ]);

echo $r->set('foo', 'bar'), PHP_EOL;
// >>> OK

echo $r->get('foo'), PHP_EOL;
// >>> bar

$r->hset('user-session:123', 'name', 'John');
$r->hset('user-session:123', 'surname', 'Smith');
$r->hset('user-session:123', 'company', 'Redis');
$r->hset('user-session:123', 'age', 29);

echo var_export($r->hgetall('user-session:123')), PHP_EOL;
/* >>>
array (
  'name' => 'John',
  'surname' => 'Smith',
  'company' => 'Redis',
  'age' => '29',
)
*/

code:
import redis
r = redis.Redis(host='localhost', port=6379, decode_responses=True)

r.set('foo', 'bar')
# True
r.get('foo')
# bar

r.hset('user-session:123', mapping={
    'name': 'John',
    "surname": 'Smith',
    "company": 'Redis',
    "age": 29
})
# True

r.hgetall('user-session:123')
# {'surname': 'Smith', 'name': 'John', 'company': 'Redis', 'age': '29'}

r.close()

code: require 'redis'

code: use redis::AsyncCommands;

code: use redis::Commands;

code:
rdb := redis.NewClient(&redis.Options{
		Addr:     "localhost:6379",
		Password: "", // no password
		DB:       0,  // use default DB
		Protocol: 2,
	})

	ctx := context.Background()

code: RedisClient jedis = new RedisClient("redis://localhost:6379");

code: r = Redis.new

code:
err := rdb.Set(ctx, "foo", "bar", 0).Err()
	if err != nil {
		panic(err)
	}

	val, err := rdb.Get(ctx, "foo").Result()
	if err != nil {
		panic(err)
	}
	fmt.Println("foo", val) // >>> foo bar

code:
String res1 = jedis.set("bike:1", "Deimos");
        System.out.println(res1); // >>> OK

        String res2 = jedis.get("bike:1");
        System.out.println(res2); // >>> Deimos

code:
hashFields := []string{
		"model", "Deimos",
		"brand", "Ergonom",
		"type", "Enduro bikes",
		"price", "4972",
	}

	res1, err := rdb.HSet(ctx, "bike:1", hashFields).Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res1) // >>> 4

	res2, err := rdb.HGet(ctx, "bike:1", "model").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res2) // >>> Deimos

	res3, err := rdb.HGet(ctx, "bike:1", "price").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res3) // >>> 4972

	res4, err := rdb.HGetAll(ctx, "bike:1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res4)
	// >>> map[brand:Ergonom model:Deimos price:4972 type:Enduro bikes]

code:
import io.lettuce.core.*;
import io.lettuce.core.api.StatefulRedisConnection;
import io.lettuce.core.api.sync.RedisCommands;

public class ConnectBasicTest {

    public void connectBasic() {
        RedisURI uri = RedisURI.Builder
                .redis("localhost", 6379)
                .build();

        RedisClient client = RedisClient.create(uri);
        StatefulRedisConnection<String, String> connection = client.connect();
        RedisCommands<String, String> commands = connection.sync();

        commands.set("foo", "bar");
        String result = commands.get("foo");
        System.out.println(result); // >>> bar

        connection.close();
        client.shutdown();
    }
}

code:
Map<String, String> hash = new HashMap<>();
        hash.put("name", "John");
        hash.put("surname", "Smith");
        hash.put("company", "Redis");
        hash.put("age", "29");

        Long res3 = jedis.hset("user-session:123", hash);
        System.out.println(res3); // >>> 4

        Map<String, String> res4 = jedis.hgetAll("user-session:123");
        System.out.println(res4);
        // >>> {name=John, surname=Smith, company=Redis, age=29}

code:
require 'redis'

r = Redis.new

r.set 'foo', 'bar'
value = r.get('foo')
puts value # >>> bar

r.hset 'user-session:123', 'name', 'John'
r.hset 'user-session:123', 'surname', 'Smith'
r.hset 'user-session:123', 'company', 'Redis'
r.hset 'user-session:123', 'age', 29

hash_value = r.hgetall('user-session:123')
puts hash_value
# >>> {"name"=>"John", "surname"=>"Smith", "company"=>"Redis", "age"=>"29"}

r.close()

code:
using NRedisStack;
using NRedisStack.RedisStackCommands;
using StackExchange.Redis;

public class AsyncLandingExample
{
    public async Task Run()
    {
        var muxer = await ConnectionMultiplexer.ConnectAsync("localhost:6379");
        var db = muxer.GetDatabase();

        await db.StringSetAsync("foo", "bar");
        string? fooResult = await db.StringGetAsync("foo");
        Console.WriteLine(fooResult); // >>> bar

        var hash = new HashEntry[] {
            new HashEntry("name", "John"),
            new HashEntry("surname", "Smith"),
            new HashEntry("company", "Redis"),
            new HashEntry("age", "29"),
            };
        await db.HashSetAsync("user-session:123", hash);

        var hashFields = await db.HashGetAllAsync("user-session:123");
        Console.WriteLine(String.Join("; ", hashFields));
        // >>> name: John; surname: Smith; company: Redis; age: 29
    }
}

code:
using NRedisStack;
using NRedisStack.RedisStackCommands;
using StackExchange.Redis;

public class SyncLandingExample
{
    public void Run()
    {
        var muxer = ConnectionMultiplexer.Connect("localhost:6379");
        var db = muxer.GetDatabase();

        db.StringSet("foo", "bar");
        Console.WriteLine(db.StringGet("foo")); // >>> bar

        var hash = new HashEntry[] {
            new HashEntry("name", "John"),
            new HashEntry("surname", "Smith"),
            new HashEntry("company", "Redis"),
            new HashEntry("age", "29"),
        };
        db.HashSet("user-session:123", hash);

        var hashFields = db.HashGetAll("user-session:123");
        Console.WriteLine(String.Join("; ", hashFields));
        // >>> name: John; surname: Smith; company: Redis; age: 29
    }
}

code:
connection.close();
        client.shutdown();

code: await client.quit();

code:
mod tests {
    use redis::AsyncCommands;

    async fn run() {
        let mut r = match redis::Client::open("redis://127.0.0.1") {
            Ok(client) => {
                match client.get_multiplexed_async_connection().await {
                    Ok(conn) => conn,
                    Err(e) => {
                        println!("Failed to connect to Redis: {e}");
                        return;
                    }
                }
            },
            Err(e) => {
                println!("Failed to create Redis client: {e}");
                return;
            }
        };

        if let Ok(res) = r.set("foo", "bar").await {
            let res: String = res;
            println!("{res}"); // >>> OK
        } else {
            println!("Error setting foo");
        }

        match r.get("foo").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> bar
            },
            Err(e) => {
                println!("Error getting foo: {e}");
                return;
            }
        };

        let hash_fields = [
            ("model", "Deimos"),
            ("brand", "Ergonom"),
            ("type", "Enduro bikes"),
            ("price", "4972"),
        ];

        if let Ok(res) = r.hset_multiple("bike:1", &hash_fields).await {
            let res: String = res;
            println!("{res}"); // >>> OK
        } else {
            println!("Error setting bike:1");
        }

        match r.hget("bike:1", "model").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> Deimos
            },
            Err(e) => {
                println!("Error getting bike:1 model: {e}");
                return;
            }
        }

        match r.hget("bike:1", "price").await {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> 4972
            },
            Err(e) => {
                println!("Error getting bike:1 price: {e}");
                return;
            }
        }

        match r.hgetall("bike:1").await {
            Ok(res) => {
                let res: Vec<(String, String)> = res;

                for (key, value) in res {
                    println!("{key}: {value}");
                }
                // >>> model: Deimos
                // >>> brand: Ergonom
                // >>> type: Enduro bikes
                // >>> price: 4972
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        }
    }
}

code:
mod landing_tests {
    use redis::Commands;

    fn run() {
        let mut r = match redis::Client::open("redis://127.0.0.1") {
            Ok(client) => {
                match client.get_connection() {
                    Ok(conn) => conn,
                    Err(e) => {
                        println!("Failed to connect to Redis: {e}");
                        return;
                    }
                }
            },
            Err(e) => {
                println!("Failed to create Redis client: {e}");
                return;
            }
        };

        if let Ok(res) = r.set("foo", "bar") {
            let res: String = res;
            println!("{res}");    // >>> OK
        } else {
            println!("Error setting foo");
        }

        match r.get("foo") {
            Ok(res) => {
                let res: String = res;
                println!("{res}");   // >>> bar
            },
            Err(e) => {
                println!("Error getting foo: {e}");
                return;
            }
        };

        let hash_fields = [
            ("model", "Deimos"),
            ("brand", "Ergonom"),
            ("type", "Enduro bikes"),
            ("price", "4972"),
        ];

        if let Ok(res) = r.hset_multiple("bike:1", &hash_fields) {
            let res: String = res;
            println!("{res}"); // >>> OK
        } else {
            println!("Error setting bike:1");
        }

        match r.hget("bike:1", "model") {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> Deimos
            },
            Err(e) => {
                println!("Error getting bike:1 model: {e}");
                return;
            }
        }

        match r.hget("bike:1", "price") {
            Ok(res) => {
                let res: String = res;
                println!("{res}"); // >>> 4972
            },
            Err(e) => {
                println!("Error getting bike:1 price: {e}");
                return;
            }
        }

        match r.hgetall("bike:1") {
            Ok(res) => {
                let res: Vec<(String, String)> = res;

                for (key, value) in res {
                    println!("{key}: {value}");
                }
                // >>> model: Deimos
                // >>> brand: Ergonom
                // >>> type: Enduro bikes
                // >>> price: 4972
            },
            Err(e) => {
                println!("Error getting bike:1: {e}");
                return;
            }
        }
    }
}