Setup Redis for AdonisJS Applications
Redis is an excellent choice for caching, sessions, and queues in AdonisJS applications. Here’s how to set it up and use it effectively:
Installation and Setup
First, install the Redis provider:
npm install @adonisjs/redis
node ace configure @adonisjs/redis
This will create a config/redis.ts
file and add the necessary environment variables to your .env
file.
Configuration
Update your .env
file with Redis connection details:
REDIS_CONNECTION=local
REDIS_HOST=127.0.0.1
REDIS_PORT=6379
REDIS_PASSWORD=
The config/redis.ts
file will look like this:
import { RedisConfig } from '@adonisjs/redis/types'
import Env from '@ioc:Adonis/Core/Env'
const redisConfig: RedisConfig = {
connection: Env.get('REDIS_CONNECTION'),
connections: {
local: {
host: Env.get('REDIS_HOST'),
port: Env.get('REDIS_PORT'),
password: Env.get('REDIS_PASSWORD', ''),
db: 0,
keyPrefix: '',
},
},
}
export default redisConfig
Basic Usage
In Controllers
import Redis from '@ioc:Adonis/Addons/Redis'
export default class UsersController {
public async index() {
// Check cache first
const cached = await Redis.get('users:all')
if (cached) {
return JSON.parse(cached)
}
// If not cached, fetch from database
const users = await User.all()
// Cache for 1 hour (3600 seconds)
await Redis.setex('users:all', 3600, JSON.stringify(users))
return users
}
}
Common Redis Operations
// Set a value
await Redis.set('key', 'value')
// Set with expiration
await Redis.setex('key', 300, 'value') // 5 minutes
// Get a value
const value = await Redis.get('key')
// Delete a key
await Redis.del('key')
// Check if key exists
const exists = await Redis.exists('key')
// Increment/Decrement
await Redis.incr('counter')
await Redis.decr('counter')
// Working with hashes
await Redis.hset('user:1', 'name', 'John')
const name = await Redis.hget('user:1', 'name')
// Working with lists
await Redis.lpush('queue', 'job1')
const job = await Redis.rpop('queue')
Using Redis for Sessions
Configure sessions to use Redis in config/session.ts
:
import { SessionConfig } from '@adonisjs/session/types'
const sessionConfig: SessionConfig = {
driver: 'redis',
cookieName: 'adonis-session',
clearWithBrowser: false,
age: '2h',
cookie: {
path: '/',
httpOnly: true,
sameSite: false,
},
redisConnection: 'local', // Use your Redis connection name
}
export default sessionConfig
Caching Pattern with Service Classes
Create a caching service:
// app/Services/CacheService.ts
import Redis from '@ioc:Adonis/Addons/Redis'
export default class CacheService {
public static async remember<T>(
key: string,
ttl: number,
callback: () => Promise<T>
): Promise<T> {
const cached = await Redis.get(key)
if (cached) {
return JSON.parse(cached)
}
const result = await callback()
await Redis.setex(key, ttl, JSON.stringify(result))
return result
}
public static async forget(key: string): Promise<void> {
await Redis.del(key)
}
public static async flush(pattern?: string): Promise<void> {
if (pattern) {
const keys = await Redis.keys(pattern)
if (keys.length > 0) {
await Redis.del(...keys)
}
} else {
await Redis.flushdb()
}
}
}
Use it in your controllers:
export default class PostsController {
public async index() {
return CacheService.remember('posts:all', 3600, async () => {
return await Post.query().preload('author').fetch()
})
}
}
Queue Jobs with Redis
For background jobs, you can use Bull (a Redis-based queue):
npm install bull @types/bull
Create a job:
// app/Jobs/SendEmailJob.ts
import Bull from 'bull'
import Mail from '@ioc:Adonis/Addons/Mail'
const emailQueue = new Bull('email queue', {
redis: {
host: '127.0.0.1',
port: 6379,
}
})
emailQueue.process(async (job) => {
const { email, subject, message } = job.data
await Mail.send((message) => {
message
.from('noreply@example.com')
.to(email)
.subject(subject)
.htmlView('emails/notification', { content: message })
})
})
export default emailQueue
Dispatch jobs:
import emailQueue from 'App/Jobs/SendEmailJob'
// In your controller
await emailQueue.add({
email: 'user@example.com',
subject: 'Welcome!',
message: 'Thanks for signing up!'
})
Best Practices
-
Use appropriate key naming conventions: Use colons to separate namespaces (
user:123:profile
) -
Set appropriate TTL values to prevent memory bloat
- Handle Redis connection failures gracefully:
try { const cached = await Redis.get('key') // Use cache if available } catch (error) { // Fall back to database if Redis fails console.error('Redis error:', error) return await Model.find() }
- Use pipeline for multiple operations:
const pipeline = Redis.pipeline() pipeline.set('key1', 'value1') pipeline.set('key2', 'value2') pipeline.incr('counter') await pipeline.exec()
This setup gives you a robust Redis integration with AdonisJS for caching, sessions, and background job processing.