Next.js Discord

Discord Forum

Help with unstable cache for users and how to revalidate

Unanswered
Plott Hound posted this in #help-forum
Open in Discord
Avatar
Plott HoundOP
Here i'm fetching from prisma and using unstable_cache:
import prisma from '@/db/prisma';
import { ExpandedProfile } from '@/types/ProfileType';
import { unstable_cache } from 'next/cache';

const getCachedExpandedProfile = (userId: string) => unstable_cache(
    async () => {
        console.log("Fetching expanded profile from database for user:", userId);
        try {
            const expandedProfile = await prisma.user.findUnique({
                where: {
                    id: userId,
                },
                select: {
                    age: true,
                    height: true,
                    weight: true,
                    workoutsGoal: true,
                    durationGoal: true,
                }
            });

            return expandedProfile;
        } catch (error) {
            console.error("Error in cached query for expanded profile:", error);
            return null;
        }
    },
    ['expandedProfile', userId],
    {
        tags: [`profiles_${userId}`],
        revalidate: 300,
    }
);

export default async function getExpandedProfile(userId: string): Promise<ExpandedProfile | null> {
    if (!userId) {
        return null;
    }

    return await getCachedExpandedProfile(userId)();
}

the console log indicates it is cached and only logs once so i assume the cache is working. Then in the route handler where we update the database I added revalidateTag:

import { revalidateTag } from 'next/cache'
export async function PATCH( request ) {
.......
revalidateTag(`profiles_${session.user.id}`);
        return NextResponse.json({ success: true, user: updatedUser }, { status: 200 });

Am i doing this right? It seems to be working but i want to make sure before i start modifying all my route handlers

1 Reply

Avatar
Cape lion
You seem to be on the right path. The documentation isn't very clear on unstable_cache. For example, it states: "keyParts: This is an array that identifies the cached key. It must contain globally unique values that together identify the key of the data being cached. The cache key also includes the arguments passed to the function." For me, just putting an empty array [] seems to work fine because it seems the arguments passed in are already included in the cache key and that what is provided in the array is 'in addition'... but again, it's not clear. My biggest worries are (1) a user seeing the cached data of another user because the caching mechanism does not factor the user_id (a function parameter) as part of the cache key... and (2) performance+cost... If the server is caching data for tens or hundreds of thousands of users (say 1MB each) where is that 10GB-100GB being stored? What if there are 100 tags... which translates to 1-10M tags (if for each one the userId is part of the tag) ? With a traditional SPA using react-query or redux RTK, the cache is locally distributed and offloaded from the server. have you found the approach above where you specify the userId in both the keyPart and tags satisfactory?