Caching & Performance

Enable caching, choose strategies, and optimize query performance

Enable Caching

Configure the caching layer with Redis or in-memory:

config/cache.ts
import { Stabilize, DBType } from "stabilize-orm";
// Cache-aside strategy (default)
const orm = new Stabilize(
{ type: DBType.SQLite, connectionString: "./data/app.db" },
{
enabled: true,
ttl: 120, // 2 minutes
redisUrl: "redis://localhost:6379", // optional, falls back to in-memory
cachePrefix: "myapp:", // key prefix for cache entries
strategy: "cache-aside", // check cache first, fall back to DB
}
);
// Write-through strategy
const orm2 = new Stabilize(
{ type: DBType.Postgres, connectionString: "postgresql://..." },
{
enabled: true,
ttl: 300,
strategy: "write-through", // write to cache on every DB write
}
);

Cache-Aside vs Write-Through

examples/cache-strategies.ts
// Cache-aside: Reads check cache first, writes invalidate cache
// Best for: Read-heavy workloads with infrequent writes
const user = await userRepo.findOne(1);
// First call: DB hit, result cached
// Second call: Cache hit, no DB query
await userRepo.update(1, { name: "Updated" });
// Cache invalidated, next read goes to DB
// Write-through: Writes update both DB and cache
// Best for: Mixed read/write workloads
const orm = new Stabilize(config, { enabled: true, ttl: 60, strategy: "write-through" });

Cache Statistics

examples/cache-stats.ts
// Get cache statistics
const stats = await orm.getCacheStats();
console.log("Cache hits:", stats.hits);
console.log("Cache misses:", stats.misses);
console.log("Cache keys:", stats.keys);
// Cache hit ratio
const ratio = stats.hits / (stats.hits + stats.misses) * 100;
console.log("Cache hit ratio:", ratio.toFixed(1) + "%");

Performance Tips

examples/performance.ts
// 1. Use select() to fetch only needed columns
const users = await userRepo.find()
.select("id", "name", "email")
.execute(orm.client);
// 2. Use pagination instead of fetching all records
const page = await userRepo.paginate(1, 50);
// 3. Use bulk operations for multiple inserts
await userRepo.bulkCreate(users, { batchSize: 500 });
// 4. Use indexes on frequently queried columns
// Add index in model definition:
// email: { type: DataTypes.STRING, index: "idx_email" }
// 5. Use pluck() for single-column fetches
const emails = await userRepo.pluck("email");
// 6. Use count() instead of fetching and counting
const count = await userRepo.count({ isActive: true });
// 7. Use exists() instead of count() for presence checks
const hasUsers = await userRepo.exists({ role: "admin" });
// 8. Connection pooling (built-in for Postgres/MySQL)
const poolStats = await orm.poolStats();
console.log("Pool:", poolStats);