next-cool-cache

Getting Started

Install and configure next-cool-cache in your Next.js project

Getting Started

Get up and running with next-cool-cache in about 5 minutes.

Prerequisites

  • Next.js 16.0.0+ with the App Router
  • TypeScript 5.0+ (recommended)
  • strict: true in your tsconfig.json

Installation

npm install next-cool-cache
pnpm add next-cool-cache
yarn add next-cool-cache

Step 1: Define Your Schema

Create a cache configuration file (e.g., lib/cache.ts):

import { createCache } from 'next-cool-cache';

// Define your cache schema
const schema = {
  users: {
    list: {},                              // No params needed
    byId: { _params: ['id'] as const },    // Requires id param
    byEmail: { _params: ['email'] as const },
  },
  posts: {
    list: {},
    byId: { _params: ['id'] as const },
    byAuthor: { _params: ['authorId'] as const },
  },
} as const;  // <-- Critical: Must use 'as const'!

Schema Rules

Node TypeDefinitionExample
Leaf (no params)Empty object {}list: {}
Leaf (with params)Object with _paramsbyId: { _params: ['id'] as const }
BranchNested objectusers: { list: {}, byId: {...} }

Always use as const on both the schema and params arrays. Without it, TypeScript cannot infer the literal types needed for full type safety.

Step 2: Define Scopes

Scopes let you have different cache strategies for different audiences:

const scopes = ['admin', 'public', 'user'] as const;

Common scope patterns:

  • admin - For editors/admins who need instant updates
  • public - For anonymous visitors (stale-while-revalidate)
  • user - For authenticated users viewing their own data

Step 3: Create the Cache

export const cache = createCache(schema, scopes);

Complete Example

// lib/cache.ts
import { createCache } from 'next-cool-cache';

const schema = {
  users: {
    list: {},
    byId: { _params: ['id'] as const },
  },
  posts: {
    list: {},
    byId: { _params: ['id'] as const },
    byAuthor: { _params: ['authorId'] as const },
  },
} as const;

const scopes = ['admin', 'public'] as const;

export const cache = createCache(schema, scopes);

Step 4: Use in Your Application

In Cached Functions

Use cacheTag() inside functions marked with 'use cache':

// app/users/[id]/page.tsx
import { cache } from '@/lib/cache';

async function getUser(id: string) {
  'use cache: remote';
  cache.public.users.byId.cacheTag({ id });

  const user = await db.users.findUnique({ where: { id } });
  return user;
}

export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await getUser(params.id);
  return <UserProfile user={user} />;
}

In Server Actions

Use revalidateTag() or updateTag() to invalidate cached data:

// app/actions/user.ts
'use server';

import { cache } from '@/lib/cache';

export async function updateUser(id: string, data: UserData) {
  await db.users.update({ where: { id }, data });

  // Immediate update for admins
  cache.admin.users.byId.updateTag({ id });

  // Stale-while-revalidate for public (no loading screens)
  cache.public.users.byId.revalidateTag({ id });
}

Choosing Between updateTag and revalidateTag

MethodBehaviorUser ExperienceUse When
updateTag()Expires immediatelyMay see loading stateAdmin dashboards, editors
revalidateTag()Stale-while-revalidateShows stale data while fetchingPublic pages, end users

TypeScript Configuration

For full type safety, ensure your tsconfig.json has:

{
  "compilerOptions": {
    "strict": true
  }
}

Common Issues

"Property does not exist" Error

Make sure you used as const on both the schema and scopes:

// Wrong
const schema = { users: { list: {} } };
const scopes = ['admin'];

// Correct
const schema = { users: { list: {} } } as const;
const scopes = ['admin'] as const;

"Argument is not assignable" Error

Check that your params match the schema definition:

// Schema defines: byId: { _params: ['id'] as const }

// Wrong - using wrong param name
cache.admin.users.byId.cacheTag({ userId: '123' });

// Correct
cache.admin.users.byId.cacheTag({ id: '123' });

Next Steps

Now that you have the basics set up:

On this page