Skip to main content
The @commandkit/cache plugin adds powerful caching capabilities to your CommandKit bot. Cache expensive operations, API calls, and database queries with Redis or in-memory storage.

Installation

npm install @commandkit/cache

With Redis

For production use with Redis:
npm install @commandkit/cache ioredis

Setup

1

Import and add the plugin

Import the cache plugin and add it to your CommandKit instance.
src/index.ts
import { CommandKit } from 'commandkit';
import { cache } from '@commandkit/cache';

new CommandKit({
  client,
  plugins: [cache()],
});
2

Configure cache provider (optional)

By default, the plugin uses in-memory caching. For production, use Redis:
src/index.ts
import { setCacheProvider, RedisCache } from '@commandkit/cache';

const redisCache = new RedisCache({
  host: 'localhost',
  port: 6379,
});

setCacheProvider(redisCache);
3

Use caching in your code

Use the "use cache" directive to cache function results:
src/utils/data.ts
export async function fetchExpensiveData() {
  "use cache";
  
  // This result will be cached
  const data = await db.query('SELECT * FROM users');
  return data;
}

Cache Providers

Memory Cache (Default)

The default provider stores cache in memory. Perfect for development and simple bots.
import { cache, MemoryCache, setCacheProvider } from '@commandkit/cache';

const memoryCache = new MemoryCache();
setCacheProvider(memoryCache);

new CommandKit({
  client,
  plugins: [cache()],
});
Memory cache is cleared when your bot restarts. Use Redis for persistence.

Redis Cache

Use Redis for production-grade caching with persistence and distributed support.
import { RedisCache, setCacheProvider } from '@commandkit/cache';

const redisCache = new RedisCache({
  host: 'localhost',
  port: 6379,
});

setCacheProvider(redisCache);

Using the “use cache” Directive

The "use cache" directive automatically caches function results:
src/utils/api.ts
export async function fetchUserProfile(userId: string) {
  "use cache";
  
  // Set cache lifetime
  cacheLife('1h');
  
  // Tag for selective invalidation
  cacheTag(`user:${userId}`);
  
  const profile = await api.get(`/users/${userId}`);
  return profile;
}

Cache Configuration Functions

cacheLife(ttl)
function
Sets the cache TTL (time-to-live) for the current function execution.Parameters:
  • ttl - Duration as number (milliseconds) or string (‘1h’, ‘30m’, ‘5s’)
cacheLife('30m');  // 30 minutes
cacheLife(1800000); // 30 minutes in ms
cacheTag(tag)
function
Tags the cache entry for selective invalidation.Parameters:
  • tag - String identifier for the cache group
cacheTag('user:123');
cacheTag('guild:456');
revalidateTag(tag)
async function
Invalidates all cache entries with the specified tag.Parameters:
  • tag - Tag to invalidate
Returns: Promise<void>
await revalidateTag('user:123');

Cache Management

Manual Cache Control

Access the cache provider directly for manual operations:
import { getCacheProvider } from '@commandkit/cache';

const cache = getCacheProvider();

// Set a value
await cache.set('key', { data: 'value' }, 60000); // 60 seconds

// Get a value
const entry = await cache.get('key');
if (entry) {
  console.log(entry.value);
}

// Check existence
const exists = await cache.exists('key');

// Delete a key
await cache.delete('key');

// Clear all cache
await cache.clear();

// Update expiration
await cache.expire('key', 120000); // 2 minutes

Cleanup Stale Entries

import { cleanup } from '@commandkit/cache';

// Remove entries older than 24 hours
await cleanup(24 * 60 * 60 * 1000);

// Run cleanup periodically
setInterval(() => {
  cleanup();
}, 60 * 60 * 1000); // Every hour

Examples

Caching API Responses

src/utils/weather.ts
import { cacheLife, cacheTag } from '@commandkit/cache';

export async function getWeather(city: string) {
  "use cache";
  
  cacheLife('15m'); // Weather updates every 15 minutes
  cacheTag(`weather:${city}`);
  
  const response = await fetch(`https://api.weather.com/${city}`);
  return response.json();
}

Caching Database Queries

src/utils/database.ts
import { cacheLife, cacheTag } from '@commandkit/cache';

export async function getUserStats(userId: string) {
  "use cache";
  
  cacheLife('5m');
  cacheTag(`user:${userId}`);
  
  const stats = await db.query(
    'SELECT * FROM user_stats WHERE user_id = ?',
    [userId]
  );
  
  return stats[0];
}

Invalidating Cache on Updates

src/commands/profile.ts
import { revalidateTag } from '@commandkit/cache';

export const run: CommandRunOptions = async ({ interaction }) => {
  const userId = interaction.user.id;
  
  // Update user profile
  await db.updateProfile(userId, { bio: 'New bio' });
  
  // Invalidate cached profile data
  await revalidateTag(`user:${userId}`);
  
  await interaction.reply('Profile updated!');
};

Caching Expensive Calculations

src/utils/analytics.ts
export async function calculateServerStats(guildId: string) {
  "use cache";
  
  cacheLife('1h');
  cacheTag(`guild:${guildId}:stats`);
  
  // Expensive computation
  const messages = await db.query(
    'SELECT COUNT(*) FROM messages WHERE guild_id = ?',
    [guildId]
  );
  
  const activeUsers = await db.query(
    'SELECT COUNT(DISTINCT user_id) FROM messages WHERE guild_id = ? AND created_at > NOW() - INTERVAL 7 DAY',
    [guildId]
  );
  
  return {
    totalMessages: messages[0].count,
    activeUsers: activeUsers[0].count,
  };
}

Advanced Usage

Conditional Caching

export async function fetchData(userId: string, skipCache = false) {
  "use cache";
  
  if (!skipCache) {
    cacheLife('10m');
    cacheTag(`data:${userId}`);
  } else {
    cacheLife(0); // Don't cache
  }
  
  return await api.fetch(userId);
}

Multiple Cache Tags

export async function getGuildMember(guildId: string, userId: string) {
  "use cache";
  
  cacheLife('30m');
  cacheTag(`guild:${guildId}`);
  cacheTag(`user:${userId}`);
  
  return await db.members.findOne({ guildId, userId });
}

// Invalidate all guild data
await revalidateTag(`guild:${guildId}`);

// Or just one user
await revalidateTag(`user:${userId}`);

Custom Cache Provider

Implement your own cache provider:
src/utils/custom-cache.ts
import { CacheProvider, CacheEntry } from '@commandkit/cache';

export class CustomCache extends CacheProvider {
  private store = new Map<string, CacheEntry>();
  
  async get<T>(key: string): Promise<CacheEntry<T> | undefined> {
    const entry = this.store.get(key) as CacheEntry<T>;
    
    if (entry && entry.ttl && Date.now() > entry.ttl) {
      this.store.delete(key);
      return undefined;
    }
    
    return entry;
  }
  
  async set<T>(key: string, value: T, ttl?: number): Promise<void> {
    this.store.set(key, {
      value,
      ttl: ttl ? Date.now() + ttl : undefined,
    });
  }
  
  async exists(key: string): Promise<boolean> {
    return this.store.has(key);
  }
  
  async delete(key: string): Promise<void> {
    this.store.delete(key);
  }
  
  async clear(): Promise<void> {
    this.store.clear();
  }
  
  async expire(key: string, ttl: number): Promise<void> {
    const entry = this.store.get(key);
    if (entry) {
      entry.ttl = Date.now() + ttl;
    }
  }
}

Best Practices

Set Appropriate TTLs

Choose cache lifetimes based on data freshness requirements. Use shorter TTLs for frequently changing data.

Use Cache Tags

Tag cache entries for easy invalidation when related data changes.

Use Redis in Production

Memory cache is great for development, but use Redis for production deployments.

Monitor Cache Performance

Track cache hits/misses using CommandKit analytics to optimize your caching strategy.

API Reference

cache(options?)

Creates the cache plugin instance. Returns: [UseCacheDirectivePlugin, CachePlugin]

setCacheProvider(provider)

Sets the cache provider for CommandKit. Parameters:
  • provider - Instance of CacheProvider

getCacheProvider()

Gets the current cache provider. Returns: CacheProvider Throws: Error if cache provider is not set.

cacheLife(ttl)

Sets TTL for the current cache operation. Must be called inside a cached function. Parameters:
  • ttl - Number (milliseconds) or string (‘1h’, ‘30m’, ‘5s’)

cacheTag(tag)

Tags the current cache entry. Must be called inside a cached function. Parameters:
  • tag - String identifier

revalidateTag(tag)

Invalidates all cache entries with the specified tag. Parameters:
  • tag - Tag to invalidate
Returns: Promise<void>

cleanup(maxAge?)

Cleans up stale cache entries. Parameters:
  • maxAge - Maximum age in milliseconds (default: 24 hours)
Returns: Promise<void>

Build docs developers (and LLMs) love