ioredis の使い方

A robust, performance-focused and full-featured Redis client for Node.js.

v5.10.115.4M/週MITORM / DB
AI生成コンテンツ

この記事はAIによって生成されました。内容の正確性は保証されません。最新の情報は公式ドキュメントをご確認ください。

ioredis の使い方 — Node.js向け高機能Redisクライアント完全ガイド

一言でいうと

ioredis は、Node.js 向けの高性能かつフル機能の Redis クライアントです。Cluster、Sentinel、Pipelining、Pub/Sub、Lua スクリプティングなど Redis の主要機能をすべてサポートし、TypeScript で書かれた堅牢なライブラリです。

どんな時に使う?

  • Webアプリケーションのキャッシュ層 — セッション管理やAPIレスポンスのキャッシュなど、高速なデータアクセスが必要な場面
  • リアルタイム通信 — Pub/Sub を活用したチャット、通知、イベント配信システムの構築
  • 大規模分散システム — Redis Cluster や Sentinel を使った高可用性・スケーラブルなアーキテクチャの実装
  • ジョブキュー・レートリミッター — BullMQ などのジョブキューライブラリの内部クライアントとして(BullMQ は ioredis に依存しています)

注意: README にも記載がありますが、新規プロジェクトでは公式が node-redis を推奨しています。ioredis は安定版としてメンテナンスが継続されていますが、Redis 8 の新機能(Search、JSON、Time-Series 等)への対応は node-redis が先行しています。既存プロジェクトや Cluster/Sentinel を多用するケースでは ioredis は依然として有力な選択肢です。

インストール

# npm
npm install ioredis

# yarn
yarn add ioredis

# pnpm
pnpm add ioredis

TypeScript プロジェクトでは Node.js の型定義も追加しておきましょう(ioredis 自体は型定義を同梱しています)。

npm install --save-dev @types/node

基本的な使い方

最もよく使うパターンとして、接続・SET/GET・切断の流れを示します。

import Redis from "ioredis";

// デフォルトで localhost:6379 に接続
const redis = new Redis();

// 接続オプションを指定する場合
// const redis = new Redis({
//   host: "127.0.0.1",
//   port: 6379,
//   password: "my-top-secret",
//   db: 0,
// });

async function main() {
  // SET: キーに値をセット(TTL 60秒)
  await redis.set("user:1:name", "Taro", "EX", 60);

  // GET: 値を取得
  const name = await redis.get("user:1:name");
  console.log(name); // "Taro"

  // DEL: キーを削除
  await redis.del("user:1:name");

  // 接続を閉じる
  await redis.quit();
}

main().catch(console.error);

URL 形式での接続も可能です。

const redis = new Redis("redis://:authpassword@127.0.0.1:6380/4");

// TLS 接続の場合
const redisTls = new Redis("rediss://username:password@my-redis.example.com:6380");

よく使うAPI — ioredis の使い方を実践的に解説

1. ハッシュ操作(hset / hgetall)

ユーザー情報のようなオブジェクトを格納するのに最適です。

import Redis from "ioredis";

const redis = new Redis();

async function hashExample() {
  // 複数フィールドを一括セット
  await redis.hset("user:100", {
    name: "Taro Yamada",
    email: "taro@example.com",
    age: "30",
  });

  // 単一フィールドの取得
  const name = await redis.hget("user:100", "name");
  console.log(name); // "Taro Yamada"

  // 全フィールドを取得(Record<string, string> として返る)
  const user = await redis.hgetall("user:100");
  console.log(user);
  // { name: "Taro Yamada", email: "taro@example.com", age: "30" }

  await redis.quit();
}

hashExample();

2. Pub/Sub(publish / subscribe)

リアルタイムなメッセージ配信に使います。Subscriber 用と Publisher 用で別々の Redis インスタンスが必要な点に注意してください。

import Redis from "ioredis";

// Subscriber(購読側)
const sub = new Redis();
// Publisher(配信側)
const pub = new Redis();

sub.subscribe("notifications", (err, count) => {
  if (err) {
    console.error("Subscribe failed:", err);
    return;
  }
  console.log(`Subscribed to ${count} channel(s)`);
});

sub.on("message", (channel: string, message: string) => {
  console.log(`[${channel}] ${message}`);
  // [notifications] {"type":"alert","body":"Hello!"}
});

// 別のインスタンスからメッセージを配信
setTimeout(async () => {
  await pub.publish(
    "notifications",
    JSON.stringify({ type: "alert", body: "Hello!" })
  );
}, 1000);

3. パイプライン(pipeline)

複数コマンドをまとめて送信し、ラウンドトリップを削減します。

import Redis from "ioredis";

const redis = new Redis();

async function pipelineExample() {
  const pipeline = redis.pipeline();

  pipeline.set("key1", "value1");
  pipeline.set("key2", "value2");
  pipeline.get("key1");
  pipeline.get("key2");

  // exec() で一括実行。結果は [error, result] のタプル配列
  const results = await pipeline.exec();
  console.log(results);
  // [
  //   [null, "OK"],
  //   [null, "OK"],
  //   [null, "value1"],
  //   [null, "value2"],
  // ]

  await redis.quit();
}

pipelineExample();

4. トランザクション(multi / exec)

複数コマンドをアトミックに実行します。

import Redis from "ioredis";

const redis = new Redis();

async function transactionExample() {
  // multi() でトランザクション開始
  const results = await redis
    .multi()
    .set("account:A", "1000")
    .set("account:B", "2000")
    .decrby("account:A", 500)
    .incrby("account:B", 500)
    .exec();

  // results: [[null, "OK"], [null, "OK"], [null, 500], [null, 2500]]
  console.log(results);

  const balanceA = await redis.get("account:A");
  const balanceB = await redis.get("account:B");
  console.log({ balanceA, balanceB }); // { balanceA: "500", balanceB: "2500" }

  await redis.quit();
}

transactionExample();

5. Redis Cluster 接続

複数ノードで構成される Redis Cluster に接続する場合は Redis.Cluster を使います。

import Redis from "ioredis";

const cluster = new Redis.Cluster([
  { host: "redis-node-1", port: 6379 },
  { host: "redis-node-2", port: 6379 },
  { host: "redis-node-3", port: 6379 },
], {
  // スロットリフレッシュの間隔(ミリ秒)
  slotsRefreshTimeout: 2000,
  redisOptions: {
    password: "cluster-password",
  },
});

async function clusterExample() {
  await cluster.set("cluster-key", "hello from cluster");
  const value = await cluster.get("cluster-key");
  console.log(value); // "hello from cluster"

  await cluster.quit();
}

clusterExample();

補足: Lua スクリプティング(defineCommand)

カスタムコマンドを定義してアトミックな操作を実現できます。

import Redis from "ioredis";

const redis = new Redis();

// カスタムコマンドを定義
redis.defineCommand("addAndGet", {
  numberOfKeys: 1,
  lua: `
    local current = redis.call('get', KEYS[1])
    if current == false then current = 0 end
    local newVal = tonumber(current) + tonumber(ARGV[1])
    redis.call('set', KEYS[1], newVal)
    return newVal
  `,
});

async function luaExample() {
  await redis.set("counter", "10");

  // defineCommand で定義したコマンドを呼び出し
  // TypeScript では型アサーションが必要
  const result = await (redis as any).addAndGet("counter", 5);
  console.log(result); // 15

  await redis.quit();
}

luaExample();

類似パッケージとの比較

項目ioredisnode-redis (redis)
メンテナンス状況安定版(ベストエフォート)積極的に開発中(公式推奨)
TypeScript サポート✅ 同梱✅ 同梱
Cluster サポート✅ 組み込み✅ 組み込み
Sentinel サポート✅ 組み込み✅ 組み込み
Autopipelining
Redis Modules (JSON, Search 等)❌ 限定的✅ ファーストクラスサポート
Redis 8 新機能対応
Pub/Sub APIイベントベース(直感的)専用オブジェクト方式
利用実績Alibaba、BullMQ 等Redis 公式
npm 週間DL数非常に多い非常に多い

選定の目安:

  • 新規プロジェクトで Redis Stack / Redis 8 の機能を使いたい → node-redis
  • BullMQ を使う / 既存プロジェクトで ioredis を利用中 → ioredis
  • Cluster・Sentinel の実績重視 → ioredis(長年の安定実績)

注意点・Tips

1. Subscriber インスタンスは通常コマンドに使えない

subscribe() を呼んだインスタンスは Subscriber モードに入り、GET / SET などの通常コマンドを実行できなくなります。Pub/Sub 用と通常操作用でインスタンスを分けてください。

const sub = new Redis();  // Pub/Sub 専用
const redis = new Redis(); // 通常操作用

2. 接続エラーのハンドリング

ioredis はデフォルトで自動再接続しますが、エラーイベントのリスナーを必ず設定しましょう。リスナーがないと Node.js プロセスがクラッシュします。

const redis = new Redis({
  retryStrategy(times) {
    const delay = Math.min(times * 50, 2000);
    return delay; // null を返すと再接続を停止
  },
  maxRetriesPerRequest: 3,
});

redis.on("error", (err) => {
  console.error("Redis connection error:", err);
});

3. 戻り値はすべて文字列

Redis の GET 等で返る値は常に string | null です。数値を扱う場合は明示的にパースしてください。

await redis.set("count", "42");
const count = await redis.get("count"); // "42" (string)
const num = Number(count); // 42

4. keyPrefix で名前空間を分離

マルチテナントや環境分離に便利です。

const redis = new Redis({ keyPrefix: "myapp:" });

await redis.set("user:1", "Taro");
// 実際のキーは "myapp:user:1" になる

// ただし keys() や scan() には prefix が自動付与されないので注意

5. Autopipelining を活用する

enableAutoPipelining: true を設定すると、同一イベントループ内の複数コマンドが自動的にパイプライン化され、パフォーマンスが向上します。

const redis = new Redis({
  enableAutoPipelining: true,
});

6. quit() と disconnect() の違い

  • quit() — 保留中のコマンドをすべて処理してから接続を閉じる(推奨)
  • disconnect() — 即座に接続を切断する(保留中のコマンドはエラーになる)

まとめ

ioredis は、Node.js エコシステムにおいて長年使われてきた信頼性の高い Redis クライアントです。Cluster・Sentinel・Pipelining・Pub/Sub・Lua スクリプティングなど Redis の機能をフルに活用でき、TypeScript との相性も優れています。新規プロジェクトでは node-redis も検討すべきですが、BullMQ との組み合わせや既存資産の活用においては、ioredis は引き続き有力な選択肢です。