hono-universal-cache

Common Use Cases

Real-world examples and patterns for using hono-universal-cache

Common Use Cases

Explore common patterns and use cases for implementing caching in your Hono applications.

Dynamic Cache Names

Cache different tenants or users separately to avoid cache collisions.

import { Hono } from "hono";
import { universalCache } from "hono-universal-cache";

const app = new Hono();

app.use(
  "*",
  universalCache({
    cacheName: (c) => {
      const tenant = c.req.header("X-Tenant-ID") || "default";
      return `cache:${tenant}`;
    },
    storage,
    ttl: 3600,
  }),
);

Custom Key Generation

Ignore specific query parameters when generating cache keys.

app.use(
  "*",
  universalCache({
    cacheName: "api-cache",
    keyGenerator: (c) => {
      const url = new URL(c.req.url);
      // Ignore tracking parameters
      url.searchParams.delete("utm_source");
      url.searchParams.delete("utm_campaign");
      url.searchParams.delete("fbclid");
      return url.toString();
    },
    storage,
  }),
);

Selective Caching by Status Code

Cache successful responses and redirects, but not errors.

app.use(
  "*",
  universalCache({
    cacheName: "selective-cache",
    cacheableStatusCodes: [200, 201, 301, 302],
    storage,
  }),
);

Per-Route Caching

Apply different caching strategies to different routes.

const app = new Hono();

// Cache only API routes with short TTL
app.use(
  "/api/*",
  universalCache({
    cacheName: "api-cache",
    storage,
    ttl: 300, // 5 minutes
  }),
);

// Cache product pages with longer TTL
app.use(
  "/products/*",
  universalCache({
    cacheName: "products-cache",
    storage,
    ttl: 3600, // 1 hour
  }),
);

// No caching for admin routes
app.get("/admin/*", (c) => {
  return c.json({ admin: "data" });
});

Cache Invalidation

Manually invalidate cache entries when data changes.

import { CacheManager } from "hono-universal-cache";
import { createStorage } from "unstorage";

const storage = createStorage();
const cache = new CacheManager(storage);

app.post("/api/products/:id", async (c) => {
  const id = c.req.param("id");

  // Update product in database
  await updateProduct(id);

  // Invalidate cache for this product
  await cache.delete(`/api/products/${id}`);

  return c.json({ success: true });
});

Multi-Tenant Caching

Separate cache namespaces for different tenants.

app.use("*", async (c, next) => {
  const tenant = c.req.header("X-Tenant-ID");

  if (!tenant) {
    return c.json({ error: "Tenant ID required" }, 400);
  }

  return universalCache({
    cacheName: `tenant:${tenant}`,
    storage,
    ttl: 1800, // 30 minutes
  })(c, next);
});

API Rate Limiting with Cache

Use cache to implement simple rate limiting.

import { CacheManager } from "hono-universal-cache";

const rateLimitCache = new CacheManager(storage, 60); // 1 minute TTL

app.use("/api/*", async (c, next) => {
  const ip = c.req.header("CF-Connecting-IP") || "unknown";
  const key = `ratelimit:${ip}`;

  const count = (await rateLimitCache.get(key)) || 0;

  if (count > 100) {
    return c.json({ error: "Rate limit exceeded" }, 429);
  }

  await rateLimitCache.set(key, count + 1);
  return next();
});

Conditional Caching

Cache responses based on custom conditions.

app.use("*", async (c, next) => {
  // Don't cache authenticated requests
  const authHeader = c.req.header("Authorization");
  if (authHeader) {
    return next();
  }

  // Only cache GET requests
  if (c.req.method !== "GET") {
    return next();
  }

  return universalCache({
    cacheName: "public-cache",
    storage,
    ttl: 600, // 10 minutes
  })(c, next);
});

On this page