Utilisation du client Redis intégré à Bun
Guide du client Redis intégré de Bun : connexion, commandes typées, Pub/Sub, auto-pipelining, limitation de débit et passage à ioredis.
Bun embarque un client Redis natif importable directement — import { redis, RedisClient } from "bun" — de sorte que pour la plupart des charges de travail liées au cache, à la gestion de sessions, au pub/sub et à la limitation de débit, vous n’avez plus besoin d’ajouter ioredis ou node-redis. Le client Redis natif de Bun dispose d’une API basée sur les Promises avec une gestion intégrée des connexions, des réponses entièrement typées et la prise en charge de TLS ; il est compatible avec les versions Redis 7.2 et supérieures. Ce guide porte spécifiquement sur ce client intégré — et non sur ioredis exécuté sous Bun, ce que la plupart des tutoriels « Redis avec Bun » illustrent en réalité, sans le préciser.
La distinction est importante. Un schéma récurrent dans les tutoriels existants sur Bun et Redis consiste à exécuter bun add ioredis puis à appeler new Redis() — il s’agit là de la bibliothèque tierce, et non de l’API du runtime. Tout ce qui suit utilise l’API fournie directement par Bun.
Points clés à retenir
- Importez le client avec
import { redis, RedisClient } from "bun"; l’instanceredispar défaut litREDIS_URL, puisVALKEY_URL, et se replie surredis://localhost:6379si aucune des deux n’est définie. - Le client n’ouvre aucune connexion avant l’exécution de la première commande, pipeline automatiquement les commandes et se reconnecte avec un backoff exponentiel démarrant à 50 ms, plafonné à 2 000 ms, sur un maximum de 10 tentatives par défaut.
- À partir de Bun 1.3, le client encapsule 66 commandes Redis sous forme de méthodes typées ;
redis.send(command, argsArray)permet d’exécuter toute commande non encapsulée — c’est également ainsi que vous émettezMULTI/EXECaujourd’hui. - Le Pub/Sub monopolise une connexion ; appelez
.duplicate()pour obtenir une seconde connexion dédiée à la publication ou à l’exécution d’autres commandes. - À partir de Bun 1.3.x, le client intégré ne prend pas en charge Redis Cluster ni Sentinel ; pour ces cas d’usage, tournez-vous vers
node-redisouioredis.
Connexion avec le client Redis intégré
La voie la plus rapide est l’export redis par défaut, qui se connecte de façon paresseuse à partir des variables d’environnement. Par défaut, le client lit les informations de connexion depuis REDIS_URL, puis VALKEY_URL ; si aucune n’est définie, il se replie sur redis://localhost:6379. Aucun socket n’est ouvert tant que vous n’émettez pas la première commande.
import { redis, RedisClient } from "bun";
// Client par défaut — lit REDIS_URL / VALKEY_URL depuis l'environnement
await redis.set("hello", "world");
const result = await redis.get("hello");
// Client personnalisé avec une URL explicite
const client = new RedisClient("redis://username:password@localhost:6379");
await client.set("counter", "0");
await client.incr("counter");
Utilisez l’instance redis par défaut pour un accès à l’échelle de l’application ; instanciez votre propre RedisClient lorsque vous avez besoin d’une connexion distincte, d’options spécifiques ou d’une base de données différente. La documentation Redis de Bun répertorie l’ensemble des schémas d’URL pris en charge, notamment rediss:// et redis+tls:// pour TLS, ainsi que redis+unix:// pour les sockets Unix.
La gestion des connexions est prise en charge automatiquement :
- Aucune connexion n’est établie tant qu’une commande n’est pas exécutée ; la première commande initie la connexion, qui reste ouverte pour les commandes suivantes jusqu’à l’appel de
client.close(). - En cas de coupure, le client se rétablit de lui-même : il démarre avec un délai de 50 ms, le double à chaque tentative, plafonne le délai de reconnexion à 2 000 ms et effectue jusqu’à
maxRetriestentatives (10 par défaut). - Les commandes émises pendant une déconnexion sont mises en file d’attente lorsque
enableOfflineQueueest àtrue(valeur par défaut) et rejetées immédiatement lorsqu’il est àfalse.
Ce sont les mêmes comportements que vous auriez autrement à configurer manuellement avec ioredis.
Discover how at OpenReplay.com.
Opérations principales et le recours à send()
Le client expose des méthodes typées pour les commandes Redis courantes et convertit les réponses en valeurs JavaScript natives, vous évitant ainsi la plupart des analyses manuelles :
- les réponses entières sont renvoyées sous forme de nombres JavaScript ;
- les chaînes bulk et simples sous forme de chaînes de caractères ;
- les chaînes bulk nulles sous forme de
null; - les tableaux sous forme de tableaux JavaScript.
Une coercition spécifique à certaines commandes est également appliquée : EXISTS renvoie un booléen plutôt qu’un nombre, et SISMEMBER renvoie également un booléen.
Vous pouvez ajuster tout cela via l’objet d’options :
const client = new RedisClient("redis://localhost:6379", {
connectionTimeout: 5000, // valeur par défaut : 10000 ms
autoReconnect: true, // valeur par défaut : true
maxRetries: 10, // valeur par défaut : 10
enableOfflineQueue: true, // valeur par défaut : true
enableAutoPipelining: true, // valeur par défaut : true
tls: true,
});
// Chaînes et expiration
await redis.set("session:123", "active");
await redis.expire("session:123", 3600); // en secondes
const ttl = await redis.ttl("session:123");
// Compteurs
await redis.set("counter", "0");
await redis.incr("counter");
await redis.decr("counter");
// exists() renvoie un booléen
const present = await redis.exists("session:123"); // true
// Hashes
await redis.hmset("user:123", ["name", "Alice", "email", "alice@example.com"]);
const [name, email] = await redis.hmget("user:123", ["name", "email"]);
Toutes les commandes ne disposent pas d’une méthode dédiée. L’ensemble des opérations standard sont prises en charge — notamment les hashes, les listes et les ensembles — pour un total de 66 commandes à partir de Bun 1.3. Pour tout ce qui se situe en dehors de cet ensemble, utilisez send(). La méthode send exécute n’importe quelle commande Redis, y compris celles sans méthode dédiée ; le premier argument est le nom de la commande et le second est un tableau d’arguments sous forme de chaînes.
// Recours aux commandes brutes — nom + tableau d'arguments sous forme de chaînes
await redis.send("LPUSH", ["mylist", "value1", "value2"]);
const list = await redis.send("LRANGE", ["mylist", "0", "-1"]);
send() est également la façon dont vous exécutez des transactions aujourd’hui, ce qui constitue la principale lacune de l’API du client, abordée plus loin.
Pub/Sub avec .duplicate()
Le Pub/Sub Redis est pris en charge, mais une connexion abonnée ne peut rien faire d’autre. L’abonnement monopolise la connexion RedisClient : un client ayant des abonnements actifs ne peut appeler que subscribe(). Pour envoyer d’autres commandes, vous devez créer une connexion distincte avec .duplicate(). Le callback d’abonnement reçoit d’abord le message, puis le canal.
import { RedisClient } from "bun";
const redis = new RedisClient("redis://localhost:6379");
await redis.connect();
// Seconde connexion pour la publication / autres commandes
const subscriber = await redis.duplicate();
await subscriber.subscribe("notifications", (message, channel) => {
console.log(`[${channel}] ${message}`);
});
await redis.publish("notifications", "Hello from Bun!");
Le Pub/Sub a été ajouté dans Bun 1.2.23, et la documentation le signale encore comme expérimental — stable en pratique, mais il vaut la peine d’épingler votre version de Bun si vous en dépendez. Désabonnez-vous avec .unsubscribe() (sans argument pour effacer tous les canaux ; passez un canal ou un listener pour cibler un abonnement spécifique).
Pipelining automatique
Le client intégré effectue le pipelining par défaut — vous n’avez pas à l’activer explicitement. Le client pipeline automatiquement les commandes, améliorant les performances en envoyant plusieurs commandes en lot et en traitant les réponses au fur et à mesure de leur arrivée. Émettez plusieurs commandes avec await en parallèle (par exemple avec Promise.all) et elles partent en un seul lot plutôt qu’en autant d’allers-retours :
const [a, b, c] = await Promise.all([
redis.get("user:1:name"),
redis.get("user:2:name"),
redis.get("user:3:name"),
]);
Le pipelining automatique est là où l’écart de performance avec ioredis se creuse. Bun décrit son client Redis comme significativement plus rapide qu’ioredis, l’avantage s’accentuant à mesure que la taille des lots augmente. Les chiffres publiés et reproductibles de Bun issus des notes de version 1.2.9 le confirment : dans leur benchmark GET, Bun.redis était 44,82 % plus rapide pour des lots de 10, 58,29 % plus rapide pour des lots de 100 et 85,39 % plus rapide pour des lots de 1 000 — soit environ 1,85x pour le plus grand lot, et non un multiple fixe. (Le blog de la version 1.3 de Bun publie par ailleurs un graphique de benchmark indiquant que le client intégré atteint plus de 7,9x le débit d’ioredis — ce chiffre est donc un nombre publié par Bun lui-même, et non une simple reprise secondaire.)
Quelques commandes désactivent le pipelining automatique car elles sont à état — parmi elles AUTH, INFO, MULTI, EXEC, WATCH, SUBSCRIBE et SELECT. Pour désactiver le pipelining globalement, définissez enableAutoPipelining: false.
Patterns appliqués : cache, sessions et limitation de débit
Les patterns ci-dessous sont transposables depuis n’importe quel client Redis ; ici, ils s’exécutent entièrement sur l’API intégrée. Considérez ceci comme un petit module de service autonome.
Cache-aside. Consultez Redis en premier, revenez à la base de données en cas d’absence, puis alimentez le cache avec un TTL.
import { redis } from "bun";
async function getUser(userId: string) {
const cacheKey = `user:${userId}`;
const cached = await redis.get(cacheKey);
if (cached) return JSON.parse(cached);
const user = await db.getUser(userId); // votre source de données
await redis.set(cacheKey, JSON.stringify(user));
await redis.expire(cacheKey, 3600); // 1 heure
return user;
}
Pour le write-through, mettez à jour le cache dans la même opération que l’écriture en base de données. Pour le stale-while-revalidate, servez immédiatement la valeur en cache et actualisez-la en arrière-plan lorsque le TTL approche de son expiration.
Stockage de sessions avec TTL. Stockez les sessions sous forme de hashes et laissez Redis les expirer automatiquement.
async function createSession(userId: number, data: object) {
const sessionId = crypto.randomUUID();
const key = `session:${sessionId}`;
await redis.hmset(key, [
"userId", String(userId),
"created", String(Date.now()),
"data", JSON.stringify(data),
]);
await redis.expire(key, 86400); // 24 heures
return sessionId;
}
Limitation de débit par fenêtre glissante avec des ensembles triés. Les commandes sur les ensembles triés ne sont pas encapsulées en méthodes dédiées, ce qui en fait un cas d’usage naturel pour send(). Supprimez les entrées antérieures à la fenêtre temporelle, comptez ce qui reste, puis ajoutez la requête courante.
async function rateLimit(id: string, limit = 100, windowMs = 60_000) {
const key = `ratelimit:${id}`;
const now = Date.now();
await redis.send("ZREMRANGEBYSCORE", [key, "0", String(now - windowMs)]);
const count = Number(await redis.send("ZCARD", [key]));
if (count >= limit) return { allowed: false, remaining: 0 };
await redis.send("ZADD", [key, String(now), `${now}-${crypto.randomUUID()}`]);
await redis.expire(key, Math.ceil(windowMs / 1000));
return { allowed: true, remaining: limit - count - 1 };
}
Grâce au pipelining automatique du client, la séquence ZREMRANGEBYSCORE/ZCARD/ZADD/EXPIRE est regroupée efficacement en lot, sans nécessiter d’objets pipeline manuels.
Limites, et quand continuer à utiliser ioredis ou node-redis
Le client intégré couvre les cas d’usage courants décrits ci-dessus, mais il présente des lacunes documentées à partir de Bun 1.3.x. Les transactions (MULTI/EXEC) doivent être effectuées via des commandes brutes, et Redis Sentinel ainsi que Redis Cluster ne sont pas pris en charge. Si vous avez besoin du clustering, du basculement via Sentinel ou des modules Redis Stack (recherche, JSON, séries temporelles, structures probabilistes), tournez-vous vers une bibliothèque complète. Le ticket de migration suivi par Bun lui-même recommande node-redis comme client privilégié pour les nouveaux projets, avec ioredis comme alternative établie. Le blog de la version 1.3 indique que la prise en charge des clusters, des streams et des scripts Lua est en cours de développement — consultez donc la section Limitations de la documentation avant de présumer de l’état actuel, car cette surface évolue encore.
| Fonctionnalité | redis intégré à Bun | node-redis / ioredis |
|---|---|---|
| Étape d’installation | Aucune — fourni avec Bun | bun add node-redis / ioredis |
| Pipelining automatique | Activé par défaut | Configurable / manuel |
| Pub/Sub | Oui (expérimental, via .duplicate()) | Oui |
| Transactions (MULTI/EXEC) | Via send() brut uniquement | API native |
| Redis Cluster | Non pris en charge | Pris en charge |
| Redis Sentinel | Non pris en charge | Pris en charge |
| Modules Redis Stack | Utiliser une bibliothèque | Pris en charge par node-redis |
Un détail d’implémentation mérite une précision : la documentation décrit le client comme compilé nativement (actuellement caractérisé comme implémenté en Rust, suite au portage de Bun depuis Zig en 2026). Ce détail ne modifie pas une seule ligne de votre code applicatif — la surface d’API est identique quelle que soit la technologie sous-jacente.
Pour le cache, les sessions, le pub/sub, les compteurs et la limitation de débit, le client intégré est suffisant, et l’élimination d’une dépendance constitue un gain réel. Dès que vous avez besoin de Cluster, de Sentinel, de Redis Stack ou de flux transactionnels complexes, installez node-redis. Commencez avec import { redis } from "bun" contre un serveur local, vérifiez que l’ensemble de commandes dont vous avez besoin est couvert, et épinglez votre version de Bun afin qu’une API en évolution ne vous réserve pas de mauvaises surprises en production.
FAQ
Comment exécuter une transaction Redis avec le client intégré de Bun ?
Le client intégré de Bun ne dispose pas d'API native pour MULTI/EXEC ; vous exécutez donc les transactions via la méthode brute send(). Émettez redis.send('MULTI', []), puis vos commandes en file d'attente, puis redis.send('EXEC', []). Étant donné que MULTI, EXEC et WATCH désactivent le pipelining automatique, ils sont envoyés individuellement plutôt qu'en lot. Si vous avez besoin d'une API de transaction native plus riche, node-redis ou ioredis en proposent une.
Le client Redis intégré à Bun fonctionne-t-il avec Redis Cluster ou Sentinel ?
Non. À partir de Bun 1.3.x, le client intégré ne prend pas en charge Redis Cluster ni Redis Sentinel, conformément à la section Limitations de la documentation. Pour le clustering fragmenté, le basculement via Sentinel ou les modules Redis Stack tels que la recherche, JSON et les séries temporelles, utilisez plutôt une bibliothèque complète. Le ticket de migration de Bun recommande node-redis comme client privilégié pour les nouveaux projets, avec ioredis comme alternative établie.
Quelle est la différence entre l'import redis intégré à Bun et l'exécution d'ioredis sous Bun ?
Le client intégré est l'API du runtime accessible via import { redis, RedisClient } from 'bun', sans installation requise et avec le pipelining des commandes activé par défaut. Utiliser ioredis implique bun add ioredis et new Redis(), une bibliothèque tierce avec sa propre gestion des connexions. La plupart des tutoriels « Redis avec Bun » utilisent silencieusement ioredis. Le client intégré ne requiert aucune dépendance ; ioredis ajoute les API natives pour Cluster, Sentinel et les transactions dont le client intégré est dépourvu.
Que se passe-t-il avec les commandes envoyées pendant que le client Redis de Bun est déconnecté ?
Les commandes émises pendant que le client est déconnecté sont mises en file d'attente et rejouées une fois la connexion rétablie, car enableOfflineQueue est à true par défaut. Le client se reconnecte automatiquement en utilisant un backoff exponentiel démarrant à 50 ms, doublant à chaque tentative, plafonné à 2 000 ms, sur un maximum de 10 tentatives par défaut. Définissez enableOfflineQueue à false pour rejeter immédiatement les commandes lors d'une déconnexion plutôt que de les mettre en mémoire tampon.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k