# How to Optimize Cache Performance and Tune Cache Metrics in MiniSearch

> Optimize MiniSearch cache performance with TTL and entry limits. Monitor hit rates and tune pruning intervals for efficient query speed and storage.

- Repository: [Victor Nogueira/minisearch](https://github.com/felladrin/minisearch)
- Tags: performance
- Published: 2026-03-01

---

**To optimize cache performance in MiniSearch, configure the TTL and entry limits via `updateCacheConfig()`, monitor hit rates through the built-in `cacheMetrics` system, and adjust pruning intervals to balance storage efficiency with query speed.**

MiniSearch implements a lightweight, in-browser **IndexedDB cache** that stores text and image query results for fast retrieval. The cache is deliberately configurable, allowing you to balance result freshness, memory usage, and visibility into cache efficiency. By tuning specific parameters in [`client/modules/search.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/search.ts) and monitoring the exposed metrics, you can significantly improve the hit rate while controlling storage overhead.

## Core Cache Configuration Strategies

### Adjusting Time-to-Live (TTL) for Freshness

The **TTL** (time-to-live) parameter defines how long a cached result remains valid before eviction. In [`client/modules/search.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/search.ts) (lines 31-33), the default TTL can be overridden at runtime to match your content's update frequency.

Shorten the TTL for rapidly changing data (e.g., news feeds) or extend it for static reference material:

```typescript
import { updateCacheConfig } from "./client/modules/search";

// Set TTL to 5 minutes for fresher results
updateCacheConfig({ ttl: 5 * 60 * 1000 });

// Or extend to 24 hours for stable content
updateCacheConfig({ ttl: 24 * 60 * 60 * 1000 });

```

### Limiting Storage with maxEntries

To prevent unbounded growth in **IndexedDB**, MiniSearch enforces a **maxEntries** cap (lines 34-35). Once the limit is reached, the cache prunes the oldest entries automatically. Increase this value for high-query-volume deployments or reduce it for memory-constrained environments:

```typescript
// Increase capacity to 200 distinct queries
updateCacheConfig({ maxEntries: 200 });

// Reduce footprint on low-memory devices
updateCacheConfig({ maxEntries: 50 });

```

### Enabling and Disabling the Cache at Runtime

The **enabled** flag (line 36) provides an immediate kill switch for caching without requiring a code redeployment. This is useful for debugging or temporary troubleshooting:

```typescript
// Temporarily bypass the cache
updateCacheConfig({ enabled: false });

// Re-enable when ready
updateCacheConfig({ enabled: true });

```

## Advanced Tuning and Maintenance

### Throttling Cleanup with PRUNE_INTERVAL

MiniSearch spreads the cost of cache maintenance by running a cleanup pass only after every `PRUNE_INTERVAL` writes (line 17). This constant is defined internally and governs how aggressively the cache reclaims expired entries.

A lower interval triggers more frequent pruning, reducing storage pressure but increasing write overhead. While this constant is not yet exposed in the public API, you can modify it directly in [`client/modules/search.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/search.ts) if your deployment requires different cleanup characteristics.

### Manual Cache Clearing

For user-initiated resets or administrative functions, the `clearCache()` helper removes all IndexedDB entries immediately:

```typescript
import { clearCache } from "./client/modules/search";

async function handleReset() {
  try {
    await clearCache();
    console.log("Search cache cleared successfully");
  } catch (error) {
    console.error("Failed to clear cache:", error);
  }
}

```

## Monitoring and Metrics

### Tracking Hit Rates with cacheMetrics

The **cacheMetrics** object (lines 42-88) maintains counters for text-hits, text-misses, image-hits, image-misses, and total operations. It automatically computes hit rates and logs summaries every `METRICS_LOG_INTERVAL` operations to prevent counter overflow.

These metrics allow you to quantify the effectiveness of your TTL and maxEntries settings.

### Accessing Metrics Programmatically

Every search operation returns an object containing `textHitRate`, `imageHitRate`, and raw hit/miss counts (lines 575-581). You can capture these to display real-time statistics in your UI or log them for analysis:

```typescript
const results = await performSearch("query string");

console.log(`Text cache hit rate: ${(results.textHitRate * 100).toFixed(1)}%`);
console.log(`Image cache hit rate: ${(results.imageHitRate * 100).toFixed(1)}%`);
console.log(`Total cache operations: ${results.totalOperations}`);

```

### Resetting Metrics for Baseline Analysis

To establish a fresh performance baseline after configuration changes, call `resetMetrics()` on the internal cacheMetrics instance (lines 81-86). This zeros all counters and hit-rate calculations:

```typescript
// Access the internal metrics instance (within the search module context)
cacheMetrics.resetMetrics();

```

## HTTP Cache Headers for Static Assets

### Configuring Cache-Control in Development and Production

While the IndexedDB cache handles query results, MiniSearch also optimizes static asset delivery through the Vite preview server. The [`cacheServerHook.ts`](https://github.com/felladrin/minisearch/blob/main/cacheServerHook.ts) file (lines 9-22) injects **Cache-Control** headers based on the environment:

- **Development**: `public, max-age=86400, must-revalidate`
- **Production**: `public, max-age=31536000, immutable`
- **Disabled**: `no-cache`

Register this hook in your [`vite.config.ts`](https://github.com/felladrin/minisearch/blob/main/vite.config.ts) to enable browser-level caching for JavaScript bundles and icons:

```typescript
import { cacheServerHook } from "./server/cacheServerHook";
import { defineConfig } from "vite";

export default defineConfig({
  preview: {
    configurePreviewServer: cacheServerHook,
  },
});

```

## Summary

- **Tune freshness and capacity** by adjusting `ttl` and `maxEntries` via `updateCacheConfig()` in [`client/modules/search.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/search.ts) to match your data volatility and storage constraints.
- **Control runtime behavior** using the `enabled` flag to toggle caching without redeployment, and modify `PRUNE_INTERVAL` to balance cleanup frequency with write performance.
- **Monitor effectiveness** through the `cacheMetrics` system, which exposes `textHitRate` and `imageHitRate` on every search operation and logs aggregated statistics automatically.
- **Clear state manually** using `clearCache()` for administrative resets or user-requested purges.
- **Optimize asset delivery** by enabling the [`cacheServerHook.ts`](https://github.com/felladrin/minisearch/blob/main/cacheServerHook.ts) middleware to set long-term immutable headers for static files in production.

## Frequently Asked Questions

### How do I calculate the optimal TTL for my MiniSearch deployment?

Choose a TTL that matches your content update frequency. For real-time data like news or stock prices, set `ttl` to 300000 (5 minutes) or lower using `updateCacheConfig({ ttl: 5 * 60 * 1000 })`. For static documentation or archived content, use 86400000 (24 hours) or longer to maximize cache hits and reduce API calls.

### What happens when the cache reaches the maxEntries limit?

When the number of stored entries exceeds `maxEntries`, MiniSearch automatically prunes the oldest records to maintain the cap. This LRU-style eviction occurs during write operations and is throttled by the `PRUNE_INTERVAL` constant to prevent performance spikes.

### Can I disable caching only for specific query types?

The current implementation in [`client/modules/search.ts`](https://github.com/felladrin/minisearch/blob/main/client/modules/search.ts) provides a global `enabled` flag that affects all cached operations. To disable caching for specific query types, you would need to wrap the search call with a conditional that checks the query category before invoking the cache-enabled search function, or modify the internal `cacheResult` method to accept query-type parameters.

### Where can I view the cache hit rate in real-time?

The `performSearch()` function returns a statistics object containing `textHitRate` and `imageHitRate` as floating-point values between 0 and 1. Poll this function or intercept its return value in your application state manager to display live metrics. The internal `cacheMetrics` object also logs a summary to the console every `METRICS_LOG_INTERVAL` operations if you need historical trend analysis.