quickv
v0.1.1
Published
A fast, SQLite-backed key-value cache for Bun. No Redis required.
Maintainers
Readme
quickv
A fast, SQLite-backed key-value cache for Bun. No Redis required.
Features
- Zero dependencies - Uses Bun's built-in SQLite
- Persistent storage - Data survives restarts
- TTL support - Automatic expiration with lazy + periodic cleanup
- Atomic operations -
incr/decrare transaction-safe - Batch operations -
mget/mset/mdelfor bulk operations - Type-safe - Full TypeScript support
Installation
bun add quickvQuick Start
import { Cache } from "quickv";
const cache = new Cache();
// Basic operations
cache.set("user:1", { name: "Alice", email: "[email protected]" });
const user = cache.get<User>("user:1");
// With TTL (in seconds)
cache.set("session:abc", sessionData, 3600); // 1 hourAPI Reference
Constructor
const cache = new Cache({
path: "./cache.db", // Default: ":memory:" (in-memory)
cleanupInterval: 60_000, // Default: 60000ms (1 min). Set to 0 to disable.
});Basic Operations
| Method | Description |
| ----------------------- | ------------------------------------------------------------- |
| set(key, value, ttl?) | Store a value with optional TTL in seconds |
| get<T>(key) | Retrieve a value. Returns undefined if not found or expired |
| del(key) | Delete a key |
| has(key) | Check if a key exists and is not expired |
TTL Management
| Method | Description |
| ------------------ | ------------------------------------------------------------------------------------- |
| ttl(key) | Get remaining TTL in seconds. Returns undefined if missing, null if no expiry |
| expire(key, ttl) | Set/update expiry. Pass null to remove expiry. Returns false if key doesn't exist |
Counters
cache.incr("views"); // 1
cache.incr("views"); // 2
cache.incr("views", 5); // 7
cache.decr("views"); // 6Both preserve existing TTL on the key.
Batch Operations
// Set multiple values
cache.mset({ a: 1, b: 2, c: 3 }, ttl?);
cache.mset(new Map([["a", 1], ["b", 2]]));
cache.mset([["a", 1], ["b", 2]]);
// Get multiple values
const values = cache.mget<number>(["a", "b", "c"]); // Map<string, number>
// Delete multiple keys
cache.mdel(["a", "b"]);Utility Methods
| Method | Description |
| ---------------- | ------------------------------------------------------ |
| keys(pattern?) | List keys. Supports * and ? wildcards |
| size() | Count of non-expired entries |
| clear() | Delete all entries |
| cleanup() | Manually remove expired entries. Returns count removed |
| close() | Close database and stop cleanup timer |
Pattern Matching
cache.set("user:1", "alice");
cache.set("user:2", "bob");
cache.set("post:1", "hello");
cache.keys("user:*"); // ["user:1", "user:2"]
cache.keys("*:1"); // ["user:1", "post:1"]Persistence
// In-memory (default) - fastest, lost on restart
const cache = new Cache();
// File-based - persists across restarts
const cache = new Cache({ path: "./cache.db" });SQLite WAL mode is enabled automatically for better concurrent performance.
Performance
Benchmarked on Apple M4 Pro:
~600,000 writes/sec
~1,650,000 reads/secWhen to Use
Use quickv when:
- Single Bun instance
- Need persistent caching without external dependencies
- Want Redis-like API with zero setup
Use Redis when:
- Multiple instances need shared cache
- Need pub/sub or streams
- Distributed systems
License
MIT
