LogoLaunchSaaS

Cache

Add cache support to your app using Redis, Upstash, or Cloudflare KV

LaunchSaaS provides cache support via a split-package design. The core @launchsaas/cache package defines the interface and Cache service; each provider is a separate package that you install only when needed.

Updated: 2026-03-15

Architecture

@launchsaas/cache              ← interface + Cache class (always needed)
@launchsaas/cache-redis        ← Redis (TCP, Node.js)
@launchsaas/cache-upstash      ← Upstash Redis (HTTP, serverless / edge)
@launchsaas/cache-cloudflare-kv ← Cloudflare KV (HTTP, Cloudflare Workers)

You only add the provider package you actually use. This keeps your bundle lean and avoids pulling in SDKs (redis, @upstash/redis, cloudflare) you don't need.

LaunchSaaS ships with no cache provider installed by default — the right choice depends on your deployment target. In your own app, install whichever provider matches your infrastructure.

Adding Cache to Your App

1. Install the provider package

In your app directory pick one provider and install it:

# Node.js server (Redis)
pnpm add @launchsaas/cache-redis

# Serverless / Edge / Vercel (Upstash)
pnpm add @launchsaas/cache-upstash

# Cloudflare Workers / Pages
pnpm add @launchsaas/cache-cloudflare-kv

2. Add env variables

Add the provider's keys export to your app's env.ts so the env vars are validated at startup.

// your-app/src/env.ts
import { createEnv } from "@t3-oss/env-nextjs";

// Redis
import { keys as cacheKeys } from "@launchsaas/cache-redis/keys";

// or Upstash
// import { keys as cacheKeys } from "@launchsaas/cache-upstash/keys";

// or Cloudflare KV
// import { keys as cacheKeys } from "@launchsaas/cache-cloudflare-kv/keys";

export const env = createEnv({
  extends: [
    cacheKeys,
    // ... other keys
  ],
  // ...
});

3. Set environment variables

Redis

REDIS_URL=redis://localhost:6379
# With auth: redis://user:password@host:6379
# With TLS:  rediss://user:password@host:6379

Upstash Redis

UPSTASH_REDIS_REST_URL=https://your-endpoint.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-rest-token

Cloudflare KV

CLOUDFLARE_ACCOUNT_ID=your-account-id
CLOUDFLARE_KV_NAMESPACE_ID=your-namespace-id
CLOUDFLARE_API_TOKEN=your-api-token

4. Register in src/capabilities.ts

Open your app's src/capabilities.ts and configure the cache provider in the cache field:

// src/capabilities.ts  (your app — apps/launchsaas/src/capabilities.ts)

// Redis (Node.js TCP)
import { RedisCacheProvider } from "@launchsaas/cache-redis";
// Upstash Redis (HTTP / serverless)
// import { UpstashRedisCacheProvider } from "@launchsaas/cache-upstash";
// Cloudflare KV
// import { CloudflareKVCacheProvider } from "@launchsaas/cache-cloudflare-kv";

export const capabilities = {
  // set to null to disable cache
  cache: RedisCacheProvider.create(),
  // cache: UpstashRedisCacheProvider.create(),
  // cache: CloudflareKVCacheProvider.create(),
  // ...other capabilities
};

What Cache Unlocks

Once initialized, cache is used automatically by:

Better Auth Secondary Storage

Better Auth reads capabilities.cache in src/lib/auth/auth.ts. When non-null, sessions, API keys, and rate-limit data are stored in cache instead of the database:

Session lookup: ~5-10ms (cache hit) vs ~50-100ms (DB query)

No extra code needed — it's already wired in the template.

Custom Caching

import { capabilities } from "@/capabilities";

const { cache } = capabilities;

// Guard: only use cache if configured
if (cache) {
  await cache.set("my-key", JSON.stringify(data), 3600); // TTL in seconds
}

const raw = (await cache?.get("my-key")) ?? null;
const data = raw ? JSON.parse(raw) : null;

await cache?.delete("my-key");

Provider Comparison

RedisUpstashCloudflare KV
ProtocolTCPHTTPHTTP
Latencysub-ms~50-100 ms~50-100 ms
Edge / Workers
ServerlessLimited
Best forTraditional serversVercel / NetlifyCloudflare deployments

Provider Setup Guides

Redis — Local Dev

docker run -d -p 6379:6379 redis:7-alpine
# REDIS_URL=redis://localhost:6379

Upstash

  1. Create a database at console.upstash.com
  2. Copy the REST URL and REST Token from the database details page
  3. Set UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN

Cloudflare KV

  1. Create a KV namespace in the Cloudflare Dashboard → Workers & Pages → KV
  2. Create an API token with Workers KV Storage: Edit permission
  3. Set CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_KV_NAMESPACE_ID, CLOUDFLARE_API_TOKEN

Custom Provider

If none of the built-in providers fit your needs (e.g. Valkey, Momento, DynamoDB), create a new package following the same structure as the built-in ones.

1. Create the package

packages/cache-xxx/
├── package.json
├── tsconfig.json
└── src/
    ├── keys.ts      ← env var validation (if needed)
    ├── provider.ts  ← CacheProvider implementation
    └── index.ts     ← public exports

package.json

{
  "name": "@launchsaas/cache-xxx",
  "version": "0.1.0",
  "private": true,
  "main": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts"
  },
  "dependencies": {
    "@launchsaas/cache": "workspace:*",
    "@launchsaas/errors": "workspace:*",
    "server-only": "^0.0.1"
  }
}

src/provider.ts

import "server-only";
import type { CacheProvider } from "@launchsaas/cache";

export class XxxCacheProvider implements CacheProvider {
  readonly name = "xxx";

  async get(key: string): Promise<string | null> {
    // return the value, or null if not found
  }

  async set(key: string, value: string, ttl?: number): Promise<void> {
    // store value; honour ttl (seconds) when provided
  }

  async delete(key: string): Promise<void> {
    // remove the key
  }

  static create(): XxxCacheProvider {
    // validate config / instantiate client
    return new XxxCacheProvider();
  }
}

src/index.ts

export { XxxCacheProvider } from "./provider";
export { keys } from "./keys"; // omit if no env vars needed

The CacheProvider interface only requires three methods. ttl is optional; ignore it if your backend doesn't support expiry.

2. Add it to your app

In your app's package.json:

"@launchsaas/cache-xxx": "workspace:*"

If the provider has env vars, register its keys in src/env.ts:

import { keys as cacheKeys } from "@launchsaas/cache-xxx";

export const env = createEnv({
  extends: [cacheKeys /* ... */],
});

3. Register in capabilities.ts

// src/capabilities.ts  (apps/launchsaas/src/capabilities.ts)
import { XxxCacheProvider } from "@launchsaas/cache-xxx";

export const capabilities = {
  cache: XxxCacheProvider.create(),
  // ...other capabilities
};

Troubleshooting

"Cache not configured" error

capabilities.cache is null in capabilities.ts. Install a provider package and set it to a provider instance.

Redis connection refused

The TCP connection happens on first use (lazy). Check REDIS_URL and that your Redis server is reachable. Connection errors are logged to stderr with the prefix Redis Client Error:.

Cloudflare KV 404

Normal for keys that don't exist — the provider returns null. Verify CLOUDFLARE_KV_NAMESPACE_ID matches your actual namespace ID.