A comprehensive Node-RED node for Redis operations with flexible connection management and modern features.
Developed by Andrii Lototskyi
- Multiple Input Types: Host, port, database, username, password support string values, flow/global context, and environment variables
- Secure Credentials: String values stored encrypted in Node-RED credentials
- Runtime Resolution: Context and environment variables resolved at runtime
- SSL/TLS Support: Full SSL/TLS encryption with client certificates and custom CAs
- Advanced Configuration: JSON-based advanced options for Redis client
-
Flexible Input: All operations use
msg.payload
for parameters - Simple Format: Single keys can be passed as strings
- Object Format: Complex operations use structured objects
- Consistent Returns: Standardized response format across all operations
- GET - Retrieve value by key
- SET - Store value with optional TTL
- DEL - Delete single or multiple keys
- EXISTS - Check if single or multiple keys exist
- MATCH - Find keys by pattern using SCAN
- TTL - Get remaining time to live in seconds
- EXPIRE - Set expiration time for existing key
- PERSIST - Remove expiration from key
- INCR - Increment value by 1
- DECR - Decrement value by 1
- INCRBY - Increment value by N
- DECRBY - Decrement value by N
- LPUSH - Add element to beginning of list
- RPUSH - Add element to end of list
- LPOP - Remove and return first element
- RPOP - Remove and return last element
- LLEN - Get list length
- LRANGE - Get range of elements
- HSET - Set hash field value (single or multiple fields)
- HGET - Get hash field value
- HGETALL - Get all hash fields and values
- HDEL - Delete hash field(s)
- PUBLISH - Publish message to channel
npm install node-red-contrib-redis-variable
Or install directly through the Node-RED palette manager.
The Redis configuration node supports flexible connection parameters:
- Host: Redis server hostname or IP address
- Port: Redis server port (default: 6379)
- Database: Redis database number (default: 0)
- Cluster Mode: Enable for Redis Cluster deployments
- Username: Redis username (Redis 6.0+ ACL support)
- Password: Redis password for authentication
All connection parameters support multiple input types:
- String: Direct value stored securely in Node-RED credentials
- Flow Context: Retrieved from flow context variables
- Global Context: Retrieved from global context variables
- Environment Variable: Retrieved from environment variables
JSON object with additional ioredis connection options:
{
"connectTimeout": 10000,
"lazyConnect": true,
"keepAlive": 30000,
"family": 4,
"retryDelayOnFailover": 100
}
The module provides comprehensive SSL/TLS support for secure Redis connections:
- Enable SSL/TLS: Enable secure connection to Redis server
- Verify Certificate: Validate server certificates (recommended for production)
- Client Certificate: Client certificate for mutual TLS authentication
- Private Key: Private key corresponding to client certificate
- CA Certificate: Certificate Authority certificate for custom CAs
Basic SSL (server verification only):
Enable SSL/TLS: ✓
Verify Certificate: ✓
Client Certificate: (empty)
Private Key: (empty)
CA Certificate: (empty)
Mutual TLS (client + server authentication):
Enable SSL/TLS: ✓
Verify Certificate: ✓
Client Certificate: Your client certificate
Private Key: Your private key
CA Certificate: Custom CA if needed
Self-signed certificates:
Enable SSL/TLS: ✓
Verify Certificate: ✗ (disable for self-signed)
CA Certificate: Your self-signed CA
Environment-based SSL configuration:
Enable SSL/TLS: ✓
Client Certificate Type: Environment Variable → TLS_CLIENT_CERT
Private Key Type: Environment Variable → TLS_PRIVATE_KEY
CA Certificate Type: Environment Variable → TLS_CA_CERT
Host: Environment Variable → REDIS_HOST
Port: Environment Variable → REDIS_PORT
Password: Environment Variable → REDIS_PASSWORD
Host: Global Context → redis_config.host
Port: Global Context → redis_config.port
Password: Flow Context → redis_password
Setting up Global Context Variables:
-
In Node-RED Admin Panel:
- Go to Admin → Context → Global
- Add variables:
-
redis_config.host
=your-redis-host
-
redis_config.port
=6379
-
redis_config.password
=your-redis-password
-
-
Via Function Node:
// Set global context variables flow.set("redis_config", { host: "your-redis-host", port: 6379, password: "your-redis-password" });
-
Via HTTP API:
curl -X POST http://localhost:1880/context/global/redis_config \ -H "Content-Type: application/json" \ -d '{"host":"your-redis-host","port":6379,"password":"your-redis-password"}'
Troubleshooting Global Context:
- Ensure variable names match exactly (case-sensitive)
- Check Node-RED logs for context lookup messages
- Verify global context variables are set before Redis operations
Testing Global Context Setup:
-
Set up test variables:
// In a Function node flow.set("redis_config", { host: "localhost", port: 6379, password: "your-password" });
-
Test connection:
// In another Function node msg.payload = "test_key"; return msg;
-
Check logs:
- Enable debug mode:
NODE_RED_DEBUG=1 node-red
- Look for context lookup messages in Node-RED logs
- Verify connection parameters are correct
- Enable debug mode:
Universal Payload Interface: All Redis operations use a unified msg.payload
interface. Parameters can be passed as simple strings (for single keys) or as objects with specific properties. This provides flexibility while maintaining simplicity.
// Simple key format
msg.payload = "user:123";
// Returns: { payload: "stored_value" }
// Object format
msg.payload = {
key: "user:123"
};
// Returns: { payload: "stored_value" }
// Simple SET
msg.payload = {
key: "user:123",
value: "John Doe"
};
// Returns: { payload: { success: true, result: "OK", ttl: null } }
// SET with TTL
msg.payload = {
key: "session:abc123",
value: { userId: 42, role: "admin" },
ttl: 3600
};
// Returns: { payload: { success: true, result: "OK", ttl: 3600 } }
// Delete single key
msg.payload = {
key: "mykey"
};
// Or simple format
msg.payload = "mykey";
// Returns: { payload: { success: true, deleted: 1, keys: ["mykey"] } }
// Delete multiple keys
msg.payload = {
keys: ["key1", "key2", "key3"]
};
// Returns: { payload: { success: true, deleted: 3, keys: ["key1", "key2", "key3"] } }
// Check single key
msg.payload = "mykey";
// Or object format
msg.payload = {
key: "mykey"
};
// Returns: { payload: { exists: true, count: 1, keys: ["mykey"] } }
// Check multiple keys
msg.payload = {
keys: ["key1", "key2", "key3"]
};
// Returns: { payload: { exists: true, count: 2, keys: ["key1", "key2", "key3"] } }
// Simple pattern
msg.payload = "user:*";
// Returns: { payload: { pattern: "user:*", keys: ["user:123", "user:456"], count: 2, scanned: true } }
// Pattern with custom count
msg.payload = {
pattern: "session:*",
count: 50
};
// Returns: { payload: { pattern: "session:*", keys: ["session:abc123", "session:def456"], count: 2, limit: 50, scanned: true } }
// Pattern with pagination (cursor)
msg.payload = {
pattern: "user:*",
count: 30,
cursor: "12345"
};
// Returns: { payload: { pattern: "user:*", keys: ["user:31", "user:32"], count: 2, limit: 30, cursor: "67890", startCursor: "12345", scanned: true, truncated: false } }
// Pattern with skip (skip first N keys)
msg.payload = {
pattern: "session:*",
count: 30,
skip: 100
};
// Returns: { payload: { pattern: "session:*", keys: ["session:101", "session:102"], count: 2, limit: 30, cursor: "67890", startCursor: 0, scanned: true, truncated: false } }
// Complex patterns
msg.payload = "cache:page:*"; // All cache pages
msg.payload = "temp:*:data"; // Temporary data keys
msg.payload = "user:*:profile"; // User profiles
Advanced MATCH Features:
- Pattern Matching: Uses Redis SCAN with pattern matching for efficient key discovery
- Count Limit: Limit the number of keys returned (default: 100)
-
Cursor Pagination: Use
cursor
parameter for efficient pagination through large datasets -
Skip Keys: Use
skip
parameter to skip the first N matching keys - Performance Optimized: Uses Redis SCAN for non-blocking operation on large datasets
Response Format:
{
"pattern": "user:*",
"keys": ["user:1", "user:2", "user:3"],
"count": 3, // Number of keys returned
"limit": 50, // Requested limit
"cursor": "67890", // Next cursor for pagination
"startCursor": "0", // Starting cursor
"scanned": true, // Operation completed
"truncated": false // true if results were limited by count
}
Pagination Example:
// First request
msg.payload = {
pattern: "session:*",
count: 30
};
// Response contains cursor for next page
// Use that cursor in next request
msg.payload = {
pattern: "session:*",
count: 30,
cursor: "67890" // from previous response
};
// Continue until cursor becomes "0" (end of results)
msg.payload = "mykey";
// Returns: { payload: { key: "mykey", ttl: 3600, status: "expires in 3600 seconds" } }
msg.payload = {
key: "mykey",
ttl: 3600
};
// Returns: { payload: { success: true, key: "mykey", ttl: 3600, message: "Expiration set" } }
msg.payload = "mykey";
// Returns: { payload: { success: true, key: "mykey", message: "Expiration removed" } }
// Simple increment
msg.payload = "counter";
// Returns: { payload: { key: "counter", value: 1 } }
// Increment by amount
msg.payload = {
key: "score",
amount: 10
};
// Returns: { payload: { key: "score", value: 110, increment: 10 } }
msg.payload = {
key: "mylist",
value: "item1"
};
// Returns: { payload: { success: true, key: "mylist", length: 1, operation: "lpush" } }
msg.payload = "mylist";
// Returns: { payload: "item1" }
msg.payload = "mylist";
// Returns: { payload: { key: "mylist", length: 5 } }
msg.payload = {
key: "mylist",
start: 0,
stop: -1
};
// Returns: { payload: { key: "mylist", range: {start: 0, stop: -1}, values: ["item1", "item2", "item3"], count: 3 } }
Configure timeout in node settings. These operations run continuously and emit messages when items are available.
// Single field
msg.payload = {
key: "myhash",
field: "name",
value: "John"
};
// Returns: { payload: { success: true, key: "myhash", field: "name", created: true } }
// Multiple fields
msg.payload = {
key: "myhash",
fields: {
name: "John",
age: 30,
city: "New York"
}
};
// Returns: { payload: { success: true, key: "myhash", fields: ["name", "age", "city"], created: 3 } }
msg.payload = {
key: "myhash",
field: "name"
};
// Returns: { payload: "John" }
msg.payload = "myhash";
// Returns: { payload: { name: "John", age: "30", city: "New York" } }
// Delete single field
msg.payload = {
key: "myhash",
field: "age"
};
// Returns: { payload: { success: true, key: "myhash", deleted: 1, fields: ["age"] } }
// Delete multiple fields
msg.payload = {
key: "myhash",
fields: ["age", "city"]
};
// Returns: { payload: { success: true, key: "myhash", deleted: 2, fields: ["age", "city"] } }
msg.payload = {
channel: "mychannel",
message: "Hello World"
};
// Returns: { payload: { success: true, channel: "mychannel", subscribers: 2, message: "Hello World" } }
Configure channel in node settings. Messages are automatically emitted:
// Received message format:
{
topic: "mychannel",
payload: "Hello World"
}
Configure pattern in node settings (e.g., "news.*"):
// Received message format:
{
pattern: "news.*",
topic: "news.sports",
payload: "Sports update"
}
// Configure Lua script in node editor:
// return redis.call('GET', KEYS[1])
msg.payload = ["mykey"]; // Array of keys and arguments
// Returns: { payload: "script_result" }
Stores Redis client in flow or global context for direct access:
// Access stored instance
const redis = flow.get("redis_client");
const result = await redis.get("mykey");
The module automatically detects and handles JSON data without any configuration:
- Objects: JavaScript objects are automatically serialized to JSON strings when storing
- JSON Strings: Valid JSON strings are automatically parsed back to objects when retrieving
- Simple Values: Strings, numbers, and other simple types are handled as-is
- Arrays: Each item in Redis lists is automatically parsed if it's valid JSON
msg.payload = {
key: "user:123",
value: {
name: "John Doe",
age: 30,
preferences: {
theme: "dark",
language: "en"
}
}
};
// Automatically stored as: '{"name":"John Doe","age":30,"preferences":{"theme":"dark","language":"en"}}'
msg.payload = "user:123";
// Returns: {
// "name": "John Doe",
// "age": 30,
// "preferences": {
// "theme": "dark",
// "language": "en"
// }
// }
// Store simple string
msg.payload = {
key: "message",
value: "Hello World"
};
// Returns: "Hello World"
// Store number
msg.payload = {
key: "count",
value: 42
};
// Returns: "42"
// Store object
msg.payload = {
key: "config",
value: {
debug: true,
timeout: 5000
}
};
// Returns: {debug: true, timeout: 5000}
- Connections are automatically pooled and reused across nodes
- Each configuration creates a single connection pool
- Connections are automatically cleaned up when nodes are removed
For blocking operations (BLPOP, BRPOP, Lua scripts), enable "Force new connection" to prevent blocking other operations.
All operations include comprehensive error handling:
// Error response format:
{
payload: {
error: "Connection failed: ECONNREFUSED"
}
}
- Use Environment Variables: Store sensitive credentials in environment variables
- Enable Redis AUTH: Always use password authentication in production
- Use Redis ACLs: Implement fine-grained access control (Redis 6.0+)
- Enable SSL/TLS: Use encrypted connections for production environments
- Verify Certificates: Always verify server certificates in production
- Secure Certificate Storage: Store certificates and keys in environment variables or secure context
- Network Security: Use TLS/SSL for connections over untrusted networks
- Principle of Least Privilege: Grant minimal required permissions
// Store user session
msg.payload = {
key: "session:abc123",
value: {
userId: 456,
loginTime: new Date().toISOString(),
permissions: ["read", "write"]
},
ttl: 3600 // 1 hour expiration
};
// Producer - Add task to queue
msg.payload = {
key: "task_queue",
value: {
id: "task_001",
type: "email",
data: { to: "user@example.com", subject: "Welcome" }
}
};
// Consumer (using BLPOP)
// Configure BLPOP operation in node settings
// Automatically receives tasks as they're added
// Cache API response for 1 hour
msg.payload = {
key: "api_cache:users",
value: apiResponse,
ttl: 3600 // 1 hour
};
// Publisher
msg.payload = {
channel: "notifications:user:123",
message: {
type: "message",
from: "user:456",
content: "Hello there!"
}
};
// Subscriber automatically receives notifications
// Find all temporary keys
msg.payload = "temp:*";
// Returns: { pattern: "temp:*", keys: ["temp:cache1", "temp:cache2", "temp:session123"], count: 3, scanned: true }
// Find expired session keys
msg.payload = {
pattern: "session:*:expired",
count: 50
};
// Returns: { pattern: "session:*:expired", keys: ["session:abc:expired", "session:def:expired"], count: 2, scanned: true }
// Clean up old cache entries
msg.payload = "cache:old:*";
// Use returned keys with DEL operation for cleanup
// Simple format
msg.payload = "user:123";
// Object format
msg.payload = {
key: "user:123"
};
// Returns: "John Doe" (or stored value)
// Simple SET
msg.payload = {
key: "user:123",
value: "John Doe"
};
// SET with TTL (expires in 1 hour)
msg.payload = {
key: "session:abc123",
value: {userId: 42, role: "admin"},
ttl: 3600
};
// Returns: { success: true, result: "OK", ttl: 3600 }
// Delete single key
msg.payload = {
key: "temp:data"
};
// Delete multiple keys
msg.payload = {
keys: ["cache:page1", "cache:page2", "temp:data"]
};
// Returns: { success: true, deleted: 3, keys: [...] }
// Find all user keys
msg.payload = "user:*";
// Returns: { pattern: "user:*", keys: ["user:123", "user:456", "user:789"], count: 3, scanned: true }
// Find session keys with custom scan count
msg.payload = {
pattern: "session:*",
count: 25
};
// Returns: { pattern: "session:*", keys: ["session:abc123", "session:def456"], count: 2, scanned: true }
// Find cache keys
msg.payload = "cache:*";
// Returns: { pattern: "cache:*", keys: ["cache:page1", "cache:page2", "cache:api"], count: 3, scanned: true }
msg.payload = "session:abc123";
// Returns: { key: "session:abc123", ttl: 2847, status: "expires in 2847 seconds" }
msg.payload = {
key: "temp:data",
ttl: 1800
};
// Returns: { success: true, key: "temp:data", ttl: 1800, message: "Expiration set" }
msg.payload = "permanent:key";
// Returns: { success: true, key: "permanent:key", message: "Expiration removed" }
// Simple increment
msg.payload = "page:views";
// Returns: { key: "page:views", value: 1547 }
// Increment by amount
msg.payload = {
key: "score:player1",
amount: 100
};
// Returns: { key: "score:player1", value: 2350, increment: 100 }
msg.payload = {
key: "queue:tasks",
value: {
task: "process_order",
id: 12345
}
};
// Returns: { success: true, key: "queue:tasks", length: 8, operation: "lpush" }
msg.payload = {
key: "queue:tasks",
start: 0,
stop: 4
};
// Returns: { key: "queue:tasks", range: {start: 0, stop: 4}, values: [...], count: 5 }
msg.payload = "queue:tasks";
// Returns: {"task": "process_order", "id": 12345} (first item)
// Single field
msg.payload = {
key: "user:123",
field: "email",
value: "john.doe@example.com"
};
// Returns: { success: true, key: "user:123", field: "email", created: true }
// Multiple fields
msg.payload = {
key: "user:123",
fields: {
name: "John Doe",
age: 30,
city: "New York",
active: true
}
};
// Returns: { success: true, key: "user:123", fields: ["name", "age", "city", "active"], created: 4 }
// Get single field
msg.payload = {
key: "user:123",
field: "email"
};
// Returns: "john.doe@example.com"
// Get all fields
msg.payload = "user:123";
// Returns: { name: "John Doe", age: "30", city: "New York", email: "john.doe@example.com", active: "true" }
msg.payload = {
channel: "notifications",
message: {
type: "alert",
text: "System maintenance in 5 minutes",
timestamp: "2024-01-15T10:30:00Z"
}
};
// Returns: { success: true, channel: "notifications", subscribers: 3, message: "..." }
If you encounter the error "Protocol error, got "\u0015" as reply type byte"
, this indicates an SSL/TLS configuration problem:
Solution: Disable certificate verification in the SSL/TLS configuration:
- Enable SSL/TLS in the configuration node
- Uncheck "Verify Certificate" (Reject unauthorized certificates)
- This allows connections to servers with self-signed or invalid certificates
Common scenarios where this is needed:
- Self-signed certificates in development environments
- Local Redis servers with SSL enabled
- Cloud Redis services with custom certificates
- Test environments with temporary certificates
Security Note: Disabling certificate verification reduces security. Only use this in trusted environments or when you're certain about the server's identity.
- Connection Refused: Check Redis server is running and accessible
- Authentication Failed: Verify username/password configuration
- Timeout Errors: Increase connection timeout in advanced options
- Memory Issues: Monitor Redis memory usage and configure appropriate limits
Enable Node-RED debug mode to see detailed connection and operation logs:
DEBUG=redis* node-red
Context Debugging: Enable context debugging by setting the environment variable:
NODE_RED_DEBUG=1 node-red
Check Node-RED logs for messages like:
Context lookup - Type: global, Path: redis_config.host, Result: your-redis-host
Redis connection config - Host: your-redis-host, Port: 6379, Database: 0, Username: not set, Password: set
Common Context Issues:
- Variable not found: Check exact variable name spelling
-
Nested objects: Use dot notation (e.g.,
redis_config.host
) - Context type mismatch: Ensure correct context type is selected
- Timing issues: Set context variables before Redis operations
Contributions are welcome! Please read the contributing guidelines and submit pull requests to the GitHub repository.
MIT License - see LICENSE file for details.
-
Enhanced MATCH Operation: Added advanced pattern matching with pagination support
- Cursor Pagination: Efficient pagination through large datasets using Redis SCAN cursors
- Skip Functionality: Skip first N matching keys for offset-based pagination
- Count Limiting: Improved count parameter handling for precise result limiting
- Performance Optimization: Better SCAN integration for non-blocking operations
-
Improved Response Format: Enhanced MATCH response with pagination metadata
- Added
cursor
,startCursor
,limit
, andtruncated
fields - Better error handling and validation
- Added
- Production Ready: Removed debug logging and optimized for production use
- Updated Documentation: Comprehensive examples for all MATCH features
- Enhanced Error Handling: Better validation and error messages
- Initial release
- Complete Redis operations support
- Flexible connection management
- Modern ioredis integration
- Comprehensive documentation
Find keys by pattern using Redis SCAN:
// Find all keys starting with "user:"
msg.payload = {
operation: "match",
pattern: "user:*"
};
// Find keys with specific pattern and custom scan count
msg.payload = {
operation: "match",
pattern: "session:*:active",
count: 50 // Number of keys to scan per iteration
};
// Simple pattern matching
msg.payload = "temp:*"; // Find all keys starting with "temp:"
Response format:
{
pattern: "user:*",
keys: ["user:1", "user:2", "user:admin"],
count: 3,
scanned: true
}
Pattern examples:
-
user:*
- All keys starting with "user:" -
*:active
- All keys ending with ":active" -
session:*:data
- Keys with "session:" prefix and ":data" suffix -
temp_*
- Keys starting with "temp_"