Unstorage
unstorage provides a common API for Redis, filesystem, S3, Cloudflare KV, and many other storage drivers. Adapt an unstorage instance to ocache's small StorageInterface, then pass that adapter to any cached function or handler.
#Install
npm i ocache unstorageInstall any additional package required by your chosen unstorage driver.
#JSON adapter
Use getItem and setItem for the simplest adapter:
import type { StorageInterface } from "ocache";
import { createStorage } from "unstorage";
import redisDriver from "unstorage/drivers/redis";
const unstorage = createStorage({
driver: redisDriver({
url: process.env.REDIS_URL,
}),
});
export const cacheStorage: StorageInterface = {
get: (key) => unstorage.getItem(key),
set: (key, value, options) =>
value === null || value === undefined
? unstorage.removeItem(key)
: unstorage.setItem(key, value, { ttl: options?.ttl }),
};Use the same adapter instance wherever entries should share the backend:
import { defineCachedFunction, defineCachedHandler } from "ocache";
import { cacheStorage } from "./cache-storage";
export const getProduct = defineCachedFunction(loadProduct, {
name: "product",
maxAge: 60,
storage: cacheStorage,
});
export const productPage = defineCachedHandler(renderProductPage, {
name: "product-page",
maxAge: 60,
storage: cacheStorage,
});A nullish value means deletion in ocache, including during invalidation, so the adapter must call removeItem. The TTL passed to set is in seconds and can be forwarded to unstorage unchanged.
Important
Do not set binary: true on this adapter. setItem serializes the complete cache entry, so a Uint8Array does not necessarily return as a byte view. ocache uses base64 for binary payloads when binary is unset.
#Blob adapter
For drivers with native getItemRaw and setItemRaw, use createBlobStorage. It stores each cache entry as one framed blob while keeping a handler's response body as bytes:
import { createBlobStorage } from "ocache";
import { createStorage } from "unstorage";
import fsDriver from "unstorage/drivers/fs";
const unstorage = createStorage({
driver: fsDriver({ base: "./.cache" }),
});
export const cacheStorage = createBlobStorage({
get: (key) => unstorage.getItemRaw(key),
set: (key, value, options) =>
value === null
? unstorage.removeItem(key)
: unstorage.setItemRaw(key, value, { ttl: options?.ttl }),
});This avoids base64 expansion for binary responses and JSON escaping for text response bodies. createBlobStorage declares binary support itself; do not wrap it in an adapter that removes that declaration.
Many drivers implement raw operations natively, including filesystem and byte-oriented object stores. Other drivers may emulate them with base64. Check the selected driver's behavior before choosing between the JSON and raw adapters.
Note
getItemRaw and setItemRaw move one raw value, not an object graph. Do not pass a complete ocache entry directly to them; createBlobStorage supplies the required frame codec.
#Backend limits
Most unstorage drivers do not expose a per-entry limit through the common API. Set maxBodySize on cached handlers when upstream response sizes are not trusted:
const image = defineCachedHandler(renderImage, {
maxAge: 300,
maxBodySize: 5 * 1024 * 1024,
storage: cacheStorage,
});If your backend has a known enforced ceiling, expose it through maxEntryBytes on a plain adapter or on the backend passed to createBlobStorage. ocache then derives a safe default response-body limit from it.
#See also
- Storage — storage semantics, binary values, and shared instances
- h3 integration — use the adapter with an h3 cached handler
- Invalidation & Expiration — removing or expiring stored entries