How It Works
Understanding the caching mechanism and important notes
How It Works
Learn about the internal workings of hono-universal-cache and important considerations.
Caching Flow
The middleware follows this process for each request:
- Request arrives → Middleware generates cache key
- Check cache → Retrieve from storage if exists and not expired
- Cache hit → Return cached response immediately
- Cache miss → Execute route handler
- Check cacheability → Verify status code is cacheable
- Store response → Save text body to storage with TTL metadata (non-blocking)
- Return response → Send to client
Cache Key Generation
By default, the cache key is generated from:
- The full request URL (including query parameters)
- The HTTP method
You can customize this behavior with the keyGenerator option:
app.use(
"*",
universalCache({
cacheName: "api-cache",
keyGenerator: (c) => {
// Custom key logic
return `${c.req.method}:${c.req.url}`;
},
}),
);TTL (Time-To-Live)
When you specify a TTL, the middleware stores metadata alongside the cached response:
{
body: "response body",
status: 200,
headers: { /* response headers */ },
expiresAt: 1234567890 // Unix timestamp
}On subsequent requests, the middleware checks if the current time exceeds expiresAt and invalidates expired entries automatically.
Important Notes
Optimized for API Responses
This middleware is designed for text-based API responses:
- ✅ JSON APIs - Perfect use case
- ✅ Text responses - Works great
- ✅ HTML pages - Fully supported
- ✅ XML/RSS feeds - No problem
- ❌ Binary assets (images, PDFs, videos) - Use CDN/edge caching instead
The middleware uses response.text() for optimal storage efficiency. For static assets, use CDN caching (Cloudflare, CloudFront), object storage (S3, R2, Blob Storage), or Hono's built-in static file serving with CDN.
Storage-Only Caching
This middleware handles server-side storage caching only:
- ✅ Stores responses in Redis, KV, filesystem, etc.
- ✅ Caches based on status codes and TTL configuration
- 💡 Independent of HTTP caching headers - works purely at the storage layer
The middleware does not:
- Set or modify
Cache-Controlheaders - Respect browser cache directives
- Handle
ETagorLast-Modifiedheaders - Process
Varyheaders
If you need HTTP-level caching, you should set appropriate headers in your route handlers separately.
Non-blocking Cache Writes
Cache writes happen asynchronously and don't block responses:
- Cloudflare Workers/Vercel Edge: Uses
waitUntil()for background writes - Other runtimes: Uses promises with error handling
This means:
- The response is sent to the client immediately
- The cache write happens in the background
- Failed cache writes don't affect the response
- Subsequent requests may not see the cached value immediately
Memory Considerations
When using in-memory storage (default):
- Cache is lost on process restart
- Memory usage grows with cached responses
- Consider using LRU cache driver for automatic eviction
- Not suitable for distributed systems (each instance has its own cache)
For production use, consider persistent storage like Redis or cloud KV stores.
Cache Invalidation
The middleware provides automatic TTL-based expiration, but you may need manual invalidation for data updates:
import { CacheManager } from "hono-universal-cache";
const cache = new CacheManager(storage);
// Invalidate specific key
await cache.delete("/api/products/123");
// Clear all cache
await cache.clear();Performance Characteristics
- Cache hit: ~1-5ms (depends on storage driver)
- Cache miss: Full route handler execution time + storage write time
- Storage write: Non-blocking, doesn't affect response time
- Memory overhead: Minimal, stores only response body and metadata