Migrating from node-redis
Overview
Migrate from node-redis (redis@4.x) to @upstash/redis for automatic serialization, REST API access, and serverless-friendly architecture.
Good For
- Serverless deployments
- Eliminating manual type conversions
- Cleaner code without Buffer handling
- REST-based access (no TCP connections)
Limitations
- Different connection model (REST vs TCP)
- Command syntax differences
Examples
Basic Comparison
node-redis:
import { createClient } from "redis";
const redis = createClient({
url: "redis://localhost:6379",
});
await redis.connect();
// Manual serialization
const user = { name: "Alice", age: 30 };
await redis.set("user:1", JSON.stringify(user));
const raw = await redis.get("user:1");
const retrieved = JSON.parse(raw!);
// Numbers as strings
await redis.set("count", "42");
const count = await redis.get("count"); // "42"
const num = parseInt(count!, 10);
await redis.disconnect();@upstash/redis:
import { Redis } from "@upstash/redis";
const redis = Redis.fromEnv();
// No connect() needed
// Automatic serialization
const user = { name: "Alice", age: 30 };
await redis.set("user:1", user);
const retrieved = await redis.get("user:1");
// retrieved is already parsed
// Numbers preserved
await redis.set("count", 42);
const count = await redis.get("count"); // 42 (number)
// No disconnect() neededConnection Initialization
node-redis:
import { createClient } from "redis";
const redis = createClient({
socket: {
host: "redis.upstash.io",
port: 6379,
},
password: "your-password",
});
await redis.connect();@upstash/redis:
import { Redis } from "@upstash/redis";
const redis = new Redis({
url: process.env.UPSTASH_REDIS_REST_URL!,
token: process.env.UPSTASH_REDIS_REST_TOKEN!,
});Command Syntax
node-redis:
// SET with expiration
await redis.set("key", "value", { EX: 3600 });
// ZADD
await redis.zAdd("leaderboard", { score: 100, value: "player:1" });
// ZRANGE with scores
const results = await redis.zRangeWithScores("leaderboard", 0, 9);
// Returns: [{ value: "player:1", score: 100 }, ...]@upstash/redis:
// SET with expiration (lowercase options)
await redis.set("key", "value", { ex: 3600 });
// ZADD (member instead of value)
await redis.zadd("leaderboard", { score: 100, member: "player:1" });
// ZRANGE with scores
const results = await redis.zrange("leaderboard", 0, 9, { withScores: true });
// Returns: [{ member: "player:1", score: 100 }, ...]Hash Operations
node-redis:
await redis.hSet("user:1", "name", "Alice");
await redis.hSet("user:1", "age", "30"); // Must be string
const age = await redis.hGet("user:1", "age");
const numAge = parseInt(age!, 10);@upstash/redis:
await redis.hset("user:1", { name: "Alice", age: 30 }); // Native types
const age = await redis.hget("user:1", "age"); // Returns 30 (number)Pipelines
node-redis:
const pipeline = redis.multi();
pipeline.set("key1", "value1");
pipeline.set("key2", "value2");
pipeline.get("key1");
const results = await pipeline.exec();@upstash/redis:
const pipeline = redis.pipeline();
pipeline.set("key1", "value1");
pipeline.set("key2", "value2");
pipeline.get("key1");
const results = await pipeline.exec();Error Handling
node-redis:
try {
await redis.get("key");
} catch (error) {
console.error(error);
} finally {
await redis.disconnect();
}@upstash/redis:
try {
await redis.get("key");
} catch (error) {
console.error(error);
}
// No cleanup neededMigration Checklist
- Replace imports:
import { createClient } from "redis"→import { Redis } from "@upstash/redis" - Remove connection management:
await redis.connect()andawait redis.disconnect() - Update connection config: Use REST URL and token
- Remove
JSON.stringify/JSON.parsecalls - Update command names:
zAdd→zadd,hSet→hset(lowercase) - Update options:
EX→ex,value→memberin sorted sets - Remove type conversions: No
parseInt,parseFloatneeded