@ynode/redis
v1.3.4
Published
Fastify 5 plugin for Redis (node-redis) with automatic connection lifecycle, health checks, and namespace support.
Maintainers
Readme
@ynode/redis
Copyright (c) 2025 Michael Welter [email protected]
A better Redis Fastify plugin that uses the official Redis library
Why?
A lightweight Fastify plugin that exposes a single node‑redis client (redis package) on your Fastify instance and handles connection lifecycle (connect → ready → reconnect → close) for you.
- ✅ Uses the official
redisclient (not ioredis) - ✅ Clean Fastify integration with proper startup/shutdown hooks
- ✅ Simple API:
fastify.rediseverywhere in your app
If you are looking for the ioredis‑based plugin, see
@fastify/redis.
Installation
Install the package and its required peer dependency, redis.
npm install @ynode/redis redisBasic Usage
import redis from "@ynode/redis";
if (fastify.argv.redis) {
// connect to redis
await fastify.register(redis, { url: fastify.argv.redis });
}Usage
Register the plugin with your Fastify instance. Any options you provide are passed directly to the underlying node-redis createClient method.
import Fastify from "fastify";
import fastifyRedis from "@ynode/redis";
const fastify = Fastify({
logger: true,
});
// Register the plugin with options
fastify.register(fastifyRedis, {
url: "redis://localhost:6379",
});
// Access the redis client from the fastify instance
fastify.get("/", async (request, reply) => {
const value = await fastify.redis.get("mykey");
return { key: "mykey", value: value };
});
const start = async () => {
try {
await fastify.listen({ port: 3000 });
} catch (err) {
fastify.log.error(err);
process.exit(1);
}
};
start();Connection Lifecycle
This plugin manages Redis connection lifecycle using Fastify hooks:
- Connects during Fastify startup (
onReady) - Closes the Redis client during Fastify shutdown (
onClose)
Startup is fail-fast. If Redis cannot be reached (or startup metadata commands fail), fastify.listen() rejects and the server will not start.
Key Namespacing
Use withNamespace(namespace) as the default, concurrency-safe way to scope keys. It returns a scoped client view without mutating global fastify.redis.namespace.
await fastify.register(fastifyRedis, {
url: "redis://localhost:6379",
});
const tenantRedis = fastify.redis.withNamespace("codex");
await tenantRedis.set("status", "online"); // writes "codex:status"
await tenantRedis.get("status"); // reads "codex:status"Scoped clients can safely coexist:
const tenantA = fastify.redis.withNamespace("alpha");
const tenantB = fastify.redis.withNamespace("beta");
await tenantA.set("counter", "1"); // alpha:counter
await tenantB.set("counter", "1"); // beta:counterThe mutable fastify.redis.namespace property is still supported for backward compatibility:
fastify.redis.namespace = "klingon";
await fastify.redis.set("status", "battle-ready"); // writes "klingon:status"If future node-redis internals change in a way that prevents safe namespace interception, this plugin now fails fast at startup with REDIS_NAMESPACE_INCOMPATIBLE_CLIENT instead of silently writing unprefixed keys.
To bypass namespacing for specific operations, use raw (works for base and scoped clients):
await fastify.redis.raw.get("status"); // reads the literal key "status" (no prefix)
await fastify.redis.raw.set("status", "manual"); // writes key "status" (no prefix)
const tenantRedis = fastify.redis.withNamespace("codex");
await tenantRedis.raw.get("status"); // still unprefixedAdvanced flows inherit the scope of the client that creates them:
const tenantRedis = fastify.redis.withNamespace("codex");
const transaction = tenantRedis.multi();
transaction.set("status", "ready").get("status");
await transaction.exec(); // operates on codex:status
const pipeline = tenantRedis.multi();
pipeline.set("counter", "1").get("counter");
await pipeline.execAsPipeline(); // operates on codex:counter
const rawTransaction = tenantRedis.raw.multi();
rawTransaction.set("status", "literal");
await rawTransaction.exec(); // operates on literal "status"Health and Readiness
This plugin exposes simple probe helpers:
fastify.redis.readiness(): lightweight state snapshotfastify.redis.healthcheck(): ping-based health check that never throws
const readiness = fastify.redis.readiness();
// { isOpen: true, isReady: true, namespace: "codex" }
const health = await fastify.redis.healthcheck();
// { ok: true, ping: "PONG", latencyMs: 1, isOpen: true, isReady: true, namespace: "codex" }Options
Plugin-specific options
name(string, optional): connection name used with RedisCLIENT SETNAME. Default:@ynode/redisnamespace(string, optional): key prefix for Redis commands that operate on keys. Example:namespace: "codex"prefixes keys ascodex:<key>.
Redis client options
All other options are passed directly to the createClient function from the official redis library.
For a full list of available options, please see the official node-redis documentation.
TypeScript
This package ships TypeScript declarations, including Fastify instance augmentation for fastify.redis.
import Fastify from "fastify";
import fastifyRedis from "@ynode/redis";
const app = Fastify();
await app.register(fastifyRedis, { url: "redis://localhost:6379" });
await app.redis.set("health", "ok");Testing and CI
npm testruns project linting, unit tests, and integration tests.- Integration tests use
REDIS_URLwhen provided. - If
REDIS_URLis not set, tests try to start a localredis-serverautomatically. - CI runs on push and pull request, starts a Redis service, and executes
npm test.
License
This project is licensed under the MIT License.
