ProNextJS
    Professional Next.js Course
    Loading price
    30-Day Money-Back Guarantee
    lesson

    Database Caching Behavior

    Jack HerringtonJack Herrington

    We're going to explore the database examples with dynamic data and caching. We have already installed better-sqlite3 and have a SQLite database called test.db. Let's dive in and see how it's set up.

    Inside our SQLite database, we have a table called counts. When we run a SELECT query on it, we can see that it currently has a count of 49. Our goal is to increment this count.

    Screenshot: SQLite Database

    Creating an Uncached Version

    We'll start by creating an uncached version called db-dynamic. Let's take a look at what it's doing:

    async function getCount() {
    	const out = (await db.prepare("SELECT * FROM counts LIMIT 1").all()) as {
    		count: number;
    	}[];
    	return out[0]?.count;
    }
    
    async function setCount(count: number) {
    	await db.prepare("DELETE FROM counts").run();
    	await db.prepare("INSERT INTO counts (count) VALUES (?)").run(count);
    }
    
    async function Counter() {
    	return <div className="text-white text-2xl">Count: {await getCount()}</div>;
    }
    

    In this file, we have a function called getCount that uses better-sqlite3 to make a request to the database and retrieve the count. We also have another function called setCount that allows us to delete all the rows in the counts table and insert a new count.

    We've also created a React server function called counter that awaits the result of getCount and returns it.

    Finally, we have a page route for DatabaseDynamic and its server function increment. We're using a revalidate path here just to ensure that the page updates when we click the button. However, it's important to note that we're not using any caching in this example since it's all uncached by default.

    export default function DatabaseDynamic() {
    	async function increment() {
    		"use server";
    		await setCount((await getCount()) + 1);
    		revalidatePath("/file-counter-dynamic");
    	}
    
    	return (
    		<div className="flex gap-5">
    			<Counter />
    			<IncrementButton increment={increment} />
    		</div>
    	);
    }
    

    Our goal now is to achieve the same functionality but with dynamicIO. To do so, the only thing we need to change is going from revalidatePath to expirePath. Now, you might end up in a case where you actually need to wrap this in a suspense. As we saw before with the date stuff, that's really easy to do.

    Cache with a Tag

    Now, let's try a cache version of it. We'll go over to dvb-cached-tag. In this implementation, we'll do an on-demand invalidation because we're going to cache the count with a tag.

    The goal here is to cache the count coming from the database and then invalidate on-demand with a tag. To achieve this, follow these steps:

    1. Change the revalidateTag to expireTag.

    2. Remove the cache implementation, and go back down to just an async function called getCount.

    3. Add a cacheTag and use the "use cache" with the cache tag. In this example, the cache tag is countDB.

    async function getCount() {
    	"use cache";
    	cacheTag("count-db");
    
    	const out = (await db.prepare("SELECT * FROM counts LIMIT 1").all()) as {
    		count: number;
    	}[];
    	return out[0]?.count;
    }
    

    Now, when we go back to the example, we can see that the count is displayed and works as expected. When we hit refresh, the count comes from the cache.

    Caching Database

    To cache a database, you have a couple of options:

    1. Cache life: Use this method if you want to expire your cache based on a specific time.
    2. Expire path: Use this method if you prefer to expire your cache by path.

    Next, we're going to take a look at how to handle caching when it comes to data coming in off of a local file.

    Transcript

    Alright, so revalidate tag is going to become expire tag. And then we need to bring in cache tag, unstable cache tag as cache tag. And you can see the crazy cache thing we need to do to make Next.js 15 do this. We don't need to do really any of that. So I'm just gonna take this new date, and drop that down there, get rid of that.

    And then I'm gonna put in here, use cache, and then we'll use the cache tag with that name. Give it any name we want, we'll use cache tag date. Now, we can get rid of this cache date function. That's one of the really great things about this use cache stuff is that you can get rid of those cache functions I think the cache unstable cache function is really clunky and this is a nice way to not have to do any of that And it works with both Dynamic data like this as well as fetch data as well as database data as we'll see coming up So it's really just a much nicer way to handle caching. All right, let's give it a go.

    All right, we got our cached with tag, and that seems to work as well. Very cool. All right, in the next segment, we're gonna connect our Next.js 15 app to a database. We're gonna see how to handle caching when it comes to database requests.