Key-Value Store
CommandKit provides a built-in key-value store implementation using SQLite for persistent data storage. This guide will show you how to use the KV store effectively in your bot for storing configuration, user data, and other persistent information.
What is the KV Store?
The KV store is a simple, persistent key-value storage solution that:
- Persistent: Data is stored in a SQLite database file
- Namespaced: Organize data into logical groups using namespaces
- Type-safe: Full TypeScript support with proper typing
- Iterable: Use standard JavaScript iteration patterns
- Resource-safe: Implements disposable patterns for automatic cleanup
When to Use the KV Store
Use the KV store when you need to:
- Store user preferences and settings
- Cache frequently accessed data persistently
- Store bot configuration that needs to survive restarts
- Keep track of user statistics and progress
- Store temporary data that needs to persist between sessions
The KV store requires Node.js version that supports the node:sqlite
module. Make sure you're using a compatible Node.js version.
Basic Setup
The KV store is available directly from the CommandKit package:
import { KV, openKV } from 'commandkit/kv';
Quick Start
Here's a simple example of how to use the KV store:
import { openKV } from 'commandkit/kv';
// Create a new KV store instance (uses default database file)
const kv = openKV();
// Or create with custom database file
const kv = openKV('bot-data.db');
// Or create in-memory store for caching
const kv = openKV(':memory:');
// Store some data
kv.set('user:123', JSON.stringify({ name: 'John', level: 5 }));
// Retrieve data
const userData = kv.get('user:123');
if (userData) {
const user = JSON.parse(userData);
console.log(`User ${user.name} is level ${user.level}`);
}
// Check if a key exists
if (kv.has('user:123')) {
console.log('User data exists');
}
// Get all keys
const allKeys = kv.keys();
console.log('All stored keys:', allKeys);
// Clean up when done
kv.close();
Key Features
1. Namespaces
Organize your data into logical groups:
const userKv = kv.namespace('users');
const configKv = kv.namespace('config');
userKv.set('123', JSON.stringify({ name: 'John' }));
configKv.set('theme', 'dark');
2. Iteration Support
Use standard JavaScript iteration patterns:
// Iterate over all key-value pairs
for (const [key, value] of kv) {
console.log(`${key}: ${value}`);
}
// Convert to array
const entries = [...kv];
3. Automatic Resource Management
The KV store implements disposable patterns:
// Using with statement (automatic cleanup)
{
using kv = openKV();
kv.set('key', 'value');
} // kv is automatically closed
// Using async/await with automatic disposal (fake promise wrapper)
await using kv = openKV();
kv.set('key', 'value');
// kv is automatically closed when the block ends
The async using
statement is just a fake promise wrapper around the synchronous using
statement. The disposal is still synchronous.
4. Expiration Support
Store temporary data with automatic expiration:
// Set data with expiration (1 hour)
kv.setex('session:123', 'user_data', 60 * 60 * 1000);
// Set expiration for existing key (30 minutes)
kv.expire('user:123', 30 * 60 * 1000);
// Check time to live
const ttl = kv.ttl('user:123');
if (ttl > 0) {
console.log(`Expires in ${ttl}ms`);
}
5. Transaction Support
Execute multiple operations atomically:
kv.transaction(() => {
kv.set('user:123', JSON.stringify({ name: 'John' }));
kv.set('user:456', JSON.stringify({ name: 'Jane' }));
// If any operation fails, all changes are rolled back
});
6. Bulk Operations
Perform operations on multiple items:
// Get all data as an object (excluding expired keys)
const allData = kv.all();
console.log('All data:', allData);
// Get all values (excluding expired keys)
const values = kv.values();
console.log('All values:', values);
// Count total entries (excluding expired keys)
const count = kv.count();
console.log(`Total entries: ${count}`);
Best Practices
- Use Meaningful Keys: Use descriptive key names that make sense in your context
- Serialize Complex Data: Store objects as JSON strings
- Use Namespaces: Organize related data into namespaces
- Handle Missing Data: Always check if data exists before using it
- Clean Up Resources: Use disposable patterns or manually close connections
- Backup Important Data: Regularly backup your database files
Next Steps
- Learn about basic operations
- Explore namespaces
- Understand advanced features including transactions