agentsclimarketplace

Nfs add cache

Skill juncoding/nextjs-fullstack-starter/skills/nfs-add-cache

Claude Code plugin: scaffold and maintain lightweight back-office apps on pure Next.js (App Router) — Server Components for reads, Server Actions for writes, services in src/server/modules/. No tRPC.

Install
npx -y skills add juncoding/nextjs-fullstack-starter --skill nfs-add-cache

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

Retrofit Redis-backed cache handling into an existing project scaffolded with nextjs-fullstack-starter. Use when the user wants to add Redis, share Next.js cache across processes / deploys, speed up frequent reads, or any 'add caching to this project' request. Adds ioredis, a docker-compose redis service, wires Next.js's experimental cacheHandler to use Redis, adds a typed cache helper at src/server/lib/cache.ts, and REDIS_URL env. Refuses to run on projects that don't have the scaffolded structure.

SKILL.md

5.4 KB, as published. Nobody here has run it

Retrofit Redis-backed cache

Use when a project from nextjs-fullstack-starter (which uses Next.js's in-process cache by default) outgrows that. Typical triggers:

  • The user is deploying multiple Next.js processes / containers and wants a shared cache.
  • A blue-green deploy throws away the warm cache every release and that's becoming painful.
  • The user wants to use src/server/lib/cache.ts as a general-purpose Redis helper for non-Next.js caches too (rate limits, queues, etc.).

If the project ISN'T at one of those tipping points, push back gently — Next.js's default cache is fine until measurably not.

Pre-flight checks

Refuse if any of these is true:

  1. src/server/modules/ doesn't exist — the project wasn't scaffolded with this plugin.
  2. src/server/lib/cache.ts already exists — Redis is already wired. Suggest /nfs-review-project for an audit instead.

Plan

  1. Add ioredis to dependencies. Add @neshca/cache-handler if the user wants the Next.js cache itself to go through Redis.
  2. Add redis service to docker-compose.yml (under the cache profile so it doesn't always run).
  3. Add REDIS_URL to src/env.ts and .env.example.
  4. Write src/server/lib/cache.ts — a typed wrapper exposing get, set, del, and a cached(fn, key, ttl) helper.
  5. (Optional) Configure next.config.ts's cacheHandler to use @neshca/cache-handler against Redis.
  6. Update CLAUDE.md with the new pattern.

The cache helper

// src/server/lib/cache.ts
import "server-only";
import Redis from "ioredis";
import { env } from "@/env";
import { logger } from "@/server/lib/logger";

const log = logger.child({ module: "cache" });

let client: Redis | null = null;

function getClient(): Redis {
  if (!client && env.REDIS_URL) {
    client = new Redis(env.REDIS_URL, {
      lazyConnect: true,
      maxRetriesPerRequest: 2,
      retryStrategy: (times) => Math.min(times * 100, 2000),
    });
    client.on("error", (err) => log.warn({ err }, "redis error"));
  }
  if (!client) throw new Error("REDIS_URL not set");
  return client;
}

export const cache = {
  async get<T>(key: string): Promise<T | null> {
    try {
      const raw = await getClient().get(key);
      return raw ? (JSON.parse(raw) as T) : null;
    } catch (err) {
      log.warn({ err, key }, "cache.get failed");
      return null;
    }
  },

  async set<T>(key: string, value: T, ttlSeconds?: number): Promise<void> {
    try {
      const raw = JSON.stringify(value);
      if (ttlSeconds) await getClient().setex(key, ttlSeconds, raw);
      else await getClient().set(key, raw);
    } catch (err) {
      log.warn({ err, key }, "cache.set failed");
    }
  },

  async del(key: string): Promise<void> {
    try {
      await getClient().del(key);
    } catch (err) {
      log.warn({ err, key }, "cache.del failed");
    }
  },

  /**
   * Read-through cache wrapper. Returns the cached value if present, else
   * computes via `compute`, stores, and returns.
   */
  async cached<T>(key: string, ttlSeconds: number, compute: () => Promise<T>): Promise<T> {
    const hit = await this.get<T>(key);
    if (hit !== null) return hit;
    const fresh = await compute();
    await this.set(key, fresh, ttlSeconds);
    return fresh;
  },
};

When to reach for cache.cached vs. "use cache" directive

NeedUse
Cache a Server Component / service read for Next.js to invalidate by tag"use cache" + cacheTag + updateTag (built-in)
Cache something that isn't a server read (rate-limit counter, queue, ad-hoc key)cache.get / cache.set directly
Cache an expensive computation across processescache.cached(key, ttl, fn)

The two systems coexist — Next.js's "use cache" handles the server-render cache; cache.* is your own general-purpose Redis client.

Update CLAUDE.md

Add to the stack list:

- **Redis** via `ioredis`. Helper at `src/server/lib/cache.ts`. Use for non-Next.js caches (rate limits, queues, ad-hoc keys). Next.js's `"use cache"` + `updateTag` continue to handle server-render caching independently.

Update the architecture section to mention which keys to cache and which not (per the caching.md reference).

Verification

pnpm install
docker compose --profile cache up -d   # starts the redis container
REDIS_URL=redis://localhost:6379 pnpm verify

Anti-patterns to refuse

  • Replacing the Next.js cache wholesale with the ioredis helper. They serve different purposes. Server-render caching belongs to Next.js's primitives; ad-hoc caching is what the helper is for.
  • Caching per-user data without explicit user-scoped keys. Easy way to leak data across users. If you cache anything user-scoped, the key MUST include the userId.
  • Using cache.* to "fix" slow queries. Caching is a workaround. If a query is slow, fix the query or add an index first; only cache when there's no further optimization room.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.